mern-starter-cli
v2.1.0
Published
CLI that scaffolds a complete MERN project: Express 5 + TypeScript layered backend, RS256 JWT auth, tests, Docker, and a React/Vite + shadcn/ui frontend
Maintainers
Readme
🚀 MERN Starter CLI
A CLI that scaffolds a complete MERN stack project (MongoDB, Express, React, Node.js) with production-grade authentication, a layered TypeScript backend, tests, Docker and a modern UI.
Stop rebuilding the same foundation on every project. Get started in two minutes. ⚡
✨ Features
🔧 Backend (Express 5 + TypeScript)
- ✅ Strict TypeScript in ESM, from the first file to the last
- ✅ Layered architecture with a clear contract:
routes → validators → controllers → services → repositories → models - ✅ Production-grade auth: RS256 JWT (15 min) + opaque refresh tokens, hashed and rotated (30 days), revocable
- ✅ Two channels:
Bearerheader (mobile) and httpOnly cookies (web), the client picks - ✅ RBAC: roles and permissions re-read from the database on every request (bans take effect instantly)
- ✅ Email verification and password reset through single-use tokens (Resend)
- ✅ Account enumeration protection on login and forgot-password
- ✅ Database: MongoDB + Mongoose (TTL indexes, idempotent seed)
- ✅ 36 tests with Vitest + Supertest, on a dedicated test database
- ✅ Quality: type-aware ESLint, Prettier, husky + lint-staged, GitHub Actions CI
- ✅ Docker: dev compose (Mongo + API + front-end) and multi-stage production image
🎨 Frontend (React + Vite)
- ✅ Modern design: Tailwind CSS v4 + shadcn/ui components
- ✅ Complete pages: Login, Register, Dashboard, Profile, Forgot / Reset password, Email verification
- ✅ State management: Redux Toolkit
- ✅ Forms: React Hook Form + Yup (rules aligned with the server validators)
- ✅ Notifications: React Hot Toast
- ✅ Routing: React Router with protected routes (public / private)
- ✅ Secure session: access token kept in memory (never in
localStorage), automatic refresh on 401 and session restore on startup - ✅ Every API call already wired and working
📦 Installation
npm install -g mern-starter-cli🚀 Usage
mern-starter-cli createThe CLI asks for your project name, then:
- ✅ Creates the full structure (
client/+server/) and the git repository - ✅ Installs every dependency
- ✅ Updates the packages to their latest versions with
ncu - ✅ Configures Tailwind CSS v4 + shadcn/ui
- ✅ Copies all the pre-configured templates
- ✅ Generates your RS256 JWT keys and the backend
.env— nothing to configure by hand
Requirements: Node.js ≥ 22, and a MongoDB database (local, Atlas, or the one from the bundled docker compose).
📁 Generated project structure
my-project/
├── client/ # 🎨 React frontend
│ ├── src/
│ │ ├── api/ # API services
│ │ │ └── auth.js
│ │ ├── components/ # UI components (shadcn/ui)
│ │ │ └── ui/
│ │ ├── lib/ # Helpers
│ │ │ ├── axios.js # Axios instance, refresh interceptor
│ │ │ └── utils.js
│ │ ├── pages/ # Application pages
│ │ │ ├── Login.jsx
│ │ │ ├── Register.jsx
│ │ │ ├── Dashboard.jsx
│ │ │ ├── Profile.jsx
│ │ │ ├── ForgotPassword.jsx
│ │ │ ├── ResetPassword.jsx
│ │ │ └── VerifyEmail.jsx
│ │ ├── schemas/ # Yup validation schemas
│ │ │ ├── login.schema.js
│ │ │ ├── register.schema.js
│ │ │ └── ...
│ │ ├── slices/ # Redux slices
│ │ │ └── authSlice.js
│ │ ├── store/ # Redux store
│ │ │ └── store.js
│ │ ├── App.jsx
│ │ └── main.jsx
│ ├── .npmrc
│ ├── .env / .env.example
│ ├── jsconfig.json # @/ alias configured
│ ├── vite.config.js
│ └── package.json
│
└── server/ # 🔧 Express 5 + TypeScript backend
├── src/
│ ├── config/mongoose.ts # Connection + index synchronisation
│ ├── constants/ # ROLES, PERMISSIONS, durations, cookies, statuses
│ ├── models/ # Mongoose schemas (user, role, token, session)
│ ├── repositories/ # The only place that queries Mongoose
│ ├── services/ # All the business logic
│ ├── controllers/ # HTTP to domain translation
│ ├── routes/ # URLs + middlewares (index = table of contents)
│ ├── validators/ # express-validator (422)
│ ├── dtos/ # Input/output shapes (never a passwordHash)
│ ├── middlewares/ # jwt · role · permission · validation · errors
│ ├── exceptions/ # Typed domain errors → HTTP statuses
│ ├── utils/ # bcrypt · JWT · SHA-256 tokens · email
│ ├── app.ts # Express application (does not listen)
│ └── index.ts # Entry point (connect + listen)
├── tests/ # Vitest + Supertest (36 tests)
├── scripts/ # seed.ts · generate-keys.js
├── .github/workflows/ci.yml
├── .husky/pre-commit
├── Dockerfile · docker-compose.yml · docker-compose.prod.yml
├── eslint.config.js · .prettierrc · tsconfig.json · vitest.config.ts
├── .env / .env.example
├── README.md # Architecture, conventions and pitfalls
└── package.json🔧 Configuration and start-up
The backend .env is already generated by the CLI (JWT keys included): there is nothing to fill in before starting.
1️⃣ Backend
With Docker — MongoDB included, nothing else to install:
cd my-project/server
docker compose up --build # database + API (hot reload)
docker compose --profile client up # + the React front-endWithout Docker — with a local MongoDB or Atlas:
cd my-project/server
# Adjust MONGODB_URI in .env if your database is not on localhost:27017
npm run db:seed # creates the roles and permissions (safe to replay)
npm run devBackend environment variables (.env):
APP_NAME="My App"
PORT=5000
COOKIE_SECRET=<generated by the CLI>
MONGODB_URI="mongodb://localhost:27017/my_app"
MONGO_USER=app # used by docker compose
MONGO_PASSWORD=app_dev
MONGO_DB=my_app
JWT_PRIVATE_KEY="<generated by the CLI>" # RS256, flattened PEM
JWT_PUBLIC_KEY="<generated by the CLI>"
CLIENT_URLS=http://localhost:5173 # origins allowed by CORS
# ADMIN_EMAIL= # optional: creates an admin
# ADMIN_PASSWORD= # account on the next db:seed
# RESEND_API_KEY= # optional: without a key, emails
# EMAIL_FROM= # are printed to the logs2️⃣ Frontend
cd my-project/client
npm run devFrontend environment variables (.env):
VITE_API_URL=http://localhost:50003️⃣ Open the application
- Frontend: http://localhost:5173
- Backend API: http://localhost:5000
- Health check (API + database): http://localhost:5000/health
📚 Available API routes
All prefixed with /api/v1.
| Method | Route | Description | Auth |
| ------ | ------------------------- | ---------------------------------- | ---- |
| POST | /auth/register | Create an account (client role) | ❌ |
| POST | /auth/login | Sign in | ❌ |
| POST | /auth/refresh | Renew the tokens (rotation) | ❌ |
| POST | /auth/logout | Revoke the session | ❌ |
| POST | /auth/verify-email | Validate the address (emailed token) | ❌ |
| POST | /auth/forgot-password | Ask for a reset link | ❌ |
| POST | /auth/reset-password | Choose a new password | ❌ |
| GET | /auth/me | Profile + permissions | ✅ |
| PATCH | /auth/me | Update the profile | ✅ |
| POST | /auth/change-password | Change the password | ✅ |
| POST | /auth/resend-verification | Resend the verification email | ✅ |
| GET | /admin/ping | Canary route (admin role) | 🔒 |
| GET | /admin/stats | Counters (dedicated permission) | 🔒 |
🧪 Tests
cd my-project/server
npm test # 36 tests (unit + API)
npm run test:watch # watch mode
npm run typecheck # type checking
npm run lint # ESLintTests run against a <your_database>_test database, created and seeded automatically: your development database is never touched.
📦 Main packages included
Backend
- express 5 - web framework (native async error propagation)
- typescript + tsx - strict typing and direct execution in dev
- mongoose - MongoDB ODM
- bcryptjs - password hashing (12 rounds)
- jsonwebtoken - RS256 signed JWTs
- express-validator - input validation
- helmet - secure HTTP headers
- cors + cookie-parser - CORS with httpOnly cookies
- morgan - HTTP logging
- resend - email delivery
- vitest + supertest - tests
- eslint + prettier + husky - quality and commit hooks
Frontend
- react + react-dom - UI framework
- vite - lightning-fast build tool
- tailwindcss - CSS framework
- shadcn/ui - modern, customisable components
- react-router-dom - routing
- @reduxjs/toolkit + react-redux - state management
- axios - HTTP client
- react-hook-form - form handling
- yup - schema validation
- react-hot-toast - notifications
🎯 Key features
🔐 Complete authentication
- Sign-up with validation and a verification email
- Sign-in through RS256 JWTs, with rotating refresh tokens
- Routes protected by role and by permission
- Profile management (changing your email requires a new verification)
- Password change (signs out the other devices)
- Password reset by email, single-use token
🎨 Modern design
- Responsive interface (mobile first)
- Customisable shadcn/ui components
- Smooth animations
- Dark mode ready (Tailwind CSS)
🛡️ Security
- Passwords hashed with bcryptjs (12 rounds), never returned by the API
- RS256 signed JWTs (private key to sign, public key to verify), carrying only the id
- Opaque refresh tokens stored SHA-256 hashed: a database leak does not let anyone replay them
- Refresh token rotation: a replayed token is rejected
- httpOnly cookies +
sameSite: lax(anti-XSS and anti-CSRF), the refresh cookie limited to the auth path - Role and account status re-read from the database on every request: a ban is immediate
- Identical answers whether the email exists or not (account enumeration protection)
- Secure headers with Helmet, CORS restricted to a list of origins
⚡ Performance and robustness
- MongoDB indexes declared in the schemas and synchronised at startup
- TTL indexes: expired tokens and sessions are purged automatically
- Atomic operations on single-use tokens (no double consumption)
- Graceful server shutdown (
SIGINT/SIGTERM) - Vite optimisation, hot reload configured even inside Docker on Windows
🤝 Contributing
Contributions are welcome! Here is how:
- 🍴 Fork the project
- 🌿 Create a branch (
git checkout -b feature/AmazingFeature) - 💾 Commit your changes (
git commit -m 'Add some AmazingFeature') - 📤 Push the branch (
git push origin feature/AmazingFeature) - 🔀 Open a Pull Request
🐛 Reporting a bug
Open an issue with:
- A description of the problem
- Steps to reproduce
- Expected versus actual behaviour
- Screenshots when relevant
📄 License
MIT © Perrin Emmanuel Nzaou
👨💻 Author
Perrin Emmanuel NZAOU - Full-Stack Web Developer
- LinkedIn: Perrin Emmanuel Nzaou
- GitHub: @pnzaou
- Portfolio: Perrin Emmanuel Nzaou
⭐ Support
If this project helps you, give it a ⭐!
Built with ❤️ for the MERN developer community
