create-mern-mz
v0.1.0
Published
CLI scaffolding tool for MERN monorepo applications with Express, React, MongoDB, Turborepo, and OpenAPI
Maintainers
Readme
create-mern-mz
Scaffold a full-stack MERN monorepo in seconds.
npm create mern-mz my-projectWhat You Get
A production-ready TypeScript monorepo powered by Turborepo with:
Backend — Express 5, Mongoose, Zod validation, OpenAPI spec generation, modular architecture (controller → service → repository)
Frontend — React 19, Vite, styled-components, React Query, i18next, OpenAPI client generation, Error Boundary
Infrastructure — Docker Compose (MongoDB), pnpm workspaces, shared ESLint + Prettier config
Prerequisites
- Node.js >= 20
- pnpm
- Docker (for MongoDB)
Usage
# Interactive
npm create mern-mz
# With project name
npm create mern-mz my-projectThen:
cd my-project
pnpm db:up # Start MongoDB
pnpm dev # Start backend + frontendProject Structure
my-project/
├── apps/
│ ├── backend/
│ │ └── src/
│ │ ├── core/ # server, app, database, export-openapi
│ │ ├── shared/ # config, constants, middleware, utils
│ │ └── modules/ # feature modules (e.g. weather)
│ └── frontend/
│ └── src/
│ ├── core/ # main, app, routes
│ ├── shared/ # components, config, constants, hooks, i18n, utils
│ └── modules/ # feature modules (e.g. weather)
├── docker-compose.yml
├── turbo.json
├── tsconfig.base.json
├── pnpm-workspace.yaml
├── .eslintrc.cjs
└── .prettierrcSingle-Source Schema Pattern
Each backend module uses Zod as the single source of truth. Define your schema once — types, validation, and OpenAPI spec are all derived from it:
weather.schema.ts (you change this)
│
├──► TypeScript types (z.infer)
├──► Request validation (.safeParse in controller)
├──► OpenAPI spec (zod-to-openapi in export-openapi)
└──► Frontend types/hooks (auto-generated via @hey-api/openapi-ts)
weather.model.ts
└──► WeatherDocument interface (proper Mongoose types: ObjectId, Date)Change a field in the Zod schema → TypeScript catches every downstream mismatch at compile time → run pnpm generate:api to regenerate the frontend client.
Adding a New Module
Backend — create a module folder with these files:
modules/your-module/
your-module.schema.ts ← Zod schema (single source of truth)
your-module.model.ts ← Mongoose model + document interface
your-module.repository.ts ← Database queries
your-module.service.ts ← Business logic
your-module.controller.ts ← Request handlers (Zod validation)
your-module.routes.ts ← Express router
your-module.constants.ts ← Error messagesThen wire it up:
- Add route path in
shared/constants/routes.constants.ts - Mount routes in
core/app.ts - Register OpenAPI paths in
core/export-openapi.ts
Frontend — run pnpm generate:api to get typed hooks, then build your components:
modules/your-module/
your-module.page.tsx ← Module entry point (the page)
your-module.page.styles.ts ← Page styles
components/ ← Sub-components
hooks/ ← Custom hooks (if needed beyond generated ones)
index.ts ← Barrel export (exports the page)Add a route in core/routes.tsx and you're done.
Available Scripts
| Script | Description |
|--------|-------------|
| pnpm dev | Start all apps in development mode |
| pnpm build | Build all apps |
| pnpm test | Run tests across all apps |
| pnpm lint | Lint all apps |
| pnpm format | Format with Prettier |
| pnpm db:up | Start MongoDB via Docker |
| pnpm db:down | Stop MongoDB |
| pnpm quality | Run lint + format check + tests |
| pnpm generate:api | Generate frontend API client from backend OpenAPI spec |
Architecture
Each app follows a core/ → shared/ → modules/ convention:
- core/ — App bootstrap, entry points, routing
- shared/ — Cross-cutting: config, constants, utils, middleware, components
- modules/ — Feature slices, each with its own controller/service/repository (backend) or components/hooks/services (frontend)
A sample weather module is included in both apps as a reference implementation.
License
MIT
