xpress-generator
v2.0.0
Published
Professional Express.js project generator — scaffold a complete backend with TypeScript, Auth, Testing and more in one command
Maintainers
Readme
xpress-generator
Professional Express.js project generator. Scaffold a complete, production-ready backend in one command — clean architecture, validated env config, structured logging, optional auth, OpenAPI docs, Docker, CI, testing, and linting all wired up automatically.
npx xpress-generator create MyAppFeatures
- Clean module architecture —
src/modules/{name}/,src/shared/,src/middleware/instead of scattered flat folders - 4 databases — MongoDB, MySQL, PostgreSQL, SQL Server
- TypeScript optional — full
.tstemplates,tsconfig.json,ts-jest - Validated environment config —
src/shared/config/env.jsvalidatesprocess.envwith Zod at boot and fails fast with a clear error instead of crashing later - Structured logging —
pino(+pino-prettyin dev), request logging viapino-http - Health check —
GET /healthout of the box - Graceful shutdown —
SIGTERM/SIGINTclose the HTTP server and the DB connection cleanly - Auth is optional — JWT access tokens (15m) + refresh tokens (7d, hashed in DB, httpOnly cookie), with a real
register+loginflow backed by aUsermodel (bcrypt-hashed passwords). Skip it entirely if you're using OAuth/an external provider - Role-based access —
verifyToken+requireRole('admin')middleware - Rate limiting — strict limiter on auth routes + a general limiter on the whole API
- CORS allowlist — configurable via
ALLOWED_ORIGINS, closed by default instead of wide open - Centralized error handling —
AppError,errorHandler,catchAsync - Input validation — Zod schemas + reusable
validatemiddleware, wired into every generated CRUD route - Pagination built in —
generate:modellist endpoints support?page&?limitout of the box - Standard HTTP responses —
httpResponse.success / created / paginated / noContent - API docs — OpenAPI/Swagger UI at
GET /docs, auto-generated from route annotations - Migrations — Sequelize CLI for MySQL/PostgreSQL · custom SQL runner for SQL Server ·
db/init.sqlauto-bootstraps the database on firstdocker compose up(MySQL/PostgreSQL) - Docker ready — multi-stage
Dockerfile(non-root in production) +docker-compose.ymlper database, DB ports bound to localhost only - CI included — GitHub Actions workflow (lint, build, test) generated in every project
- Dependency security — Dependabot configured on this repo, pinned dependency versions,
npm run auditscript in every generated project - Testing ready — Jest + supertest, dedicated
tests/setup.js, realistic coverage threshold - Linting — ESLint (+
@typescript-eslintfor TS projects),.eslintignoreincluded - Pre-commit hooks — Husky + lint-staged auto-configured
- Code generators —
generate:model(full CRUD module, paginated, validated) andgenerate:middleware
Quick Start
# Interactive — prompts all questions
npx xpress-generator create
# Or pass the project name directly
npx xpress-generator create MyAppThe CLI will ask:
- Project name (PascalCase)
- Database — MongoDB · MySQL · PostgreSQL · SQLServer
- TypeScript? — Yes / No
- Include auth (JWT login/register)? — Yes / No
- Where to save — Current directory · Desktop · Downloads · Documents · Custom path
Generated Project Structure
MyApp/
├── src/
│ ├── app.js / app.ts ← Express app (exported, no listen)
│ ├── server.js / server.ts ← Entry point — listens + graceful shutdown
│ ├── config/
│ │ └── config-{db}.js ← Database connection
│ ├── shared/ ← Reusable code shared across modules
│ │ ├── config/
│ │ │ ├── env.js ← Zod-validated environment config
│ │ │ └── swagger.js ← OpenAPI spec setup
│ │ ├── errors/
│ │ │ └── AppError.js
│ │ ├── utils/
│ │ │ ├── catchAsync.js
│ │ │ ├── httpResponse.js
│ │ │ └── logger.js ← pino logger
│ │ ├── constants/
│ │ │ ├── httpStatus.js
│ │ │ └── messages.js
│ │ └── validators/
│ │ ├── validate.js
│ │ └── exampleSchema.js
│ ├── middleware/
│ │ ├── auth.js ← verifyToken, requireRole, authRateLimiter, apiLimiter
│ │ └── errorHandler.js
│ └── modules/
│ ├── {name}/ ← Index module (your project name)
│ │ ├── controller.js
│ │ ├── routes.js
│ │ ├── {name}Model.js
│ │ └── service.js
│ └── auth/ ← Auth module (only if auth is enabled)
│ ├── authController.js ← register, login, refresh, logout
│ ├── authRoutes.js
│ ├── User.js ← bcrypt-hashed password model
│ └── RefreshToken.js ← stores a SHA-256 hash, never the raw token
├── db/ ← Relational DBs only
│ ├── migrations/
│ │ └── {timestamp}-create-{name}.js ← + users / refresh_tokens if auth is enabled
│ └── init.sql ← Auto-bootstrap on first `docker compose up` (MySQL/Postgres)
├── tests/
│ ├── setup.js ← NODE_ENV=test, JWT secrets + dummy DB env for testing
│ └── indexController.test.js
├── .env
├── .eslintrc.json
├── .eslintignore
├── .gitignore
├── .github/workflows/ci.yml ← lint + build + test on push/PR
├── .husky/
│ └── pre-commit ← npx lint-staged
├── .lintstagedrc.json
├── .sequelizerc ← (MySQL / PostgreSQL only)
├── .xpress.json ← project metadata for generate commands
├── .dockerignore
├── Dockerfile ← Multi-stage build, non-root in production
├── docker-compose.yml ← DB service (localhost-only) + app
├── jest.config.js
└── package.jsonTypeScript projects use
.tsextensions, includetsconfig.json, and scripts usets-node.
npm Scripts (generated project)
| Script | Description |
|--------|-------------|
| npm run dev | Start with nodemon (JS) or ts-node (TS) |
| npm start | Start production server |
| npm test | Run Jest with coverage |
| npm run test:watch | Run Jest in watch mode |
| npm run lint | Run ESLint |
| npm run build | Compile TypeScript to dist/ (TS only) |
| npm run audit | Check dependencies for known vulnerabilities |
| npm run db:migrate | Run pending migrations (relational DBs only) |
| npm run db:migrate:undo | Roll back last migration (MySQL / PostgreSQL) |
CLI Commands
# Create a new project
npx xpress-generator create [name]
# Generate a full CRUD module (model + service + controller + routes + schema, paginated & validated)
npx xpress-generator generate:model <ModelName>
npx xpress-generator g:model <ModelName> # alias
# Generate a custom middleware
npx xpress-generator generate:middleware <name>
npx xpress-generator g:middleware <name> # aliasgenerate:model output
Running xpress generate:model Product inside a project creates:
src/modules/product/
├── productModel.js ← DB model (Mongoose / Sequelize / mssql)
├── service.js ← getAll (paginated), getById, create, update, remove
├── schema.js ← Zod validation schema matching the model fields
├── controller.js ← CRUD handlers via catchAsync
└── routes.js ← Express router, validated + auth-protected, OpenAPI-annotated
db/migrations/{ts}-create-product.js ← (MySQL / PostgreSQL)
db/migrations/{ts}-create-product.sql ← (SQL Server)GET /products?page=1&limit=20 returns a paginated response with meta: { page, limit, total, totalPages }.
Auth API (optional)
If you answer "yes" to the auth prompt, the generated project includes a ready-to-use, real auth layer backed by a User model:
| Method | Route | Description |
|--------|-------|-------------|
| POST | /api/auth/register | Creates a user (bcrypt-hashed password) and returns accessToken + sets refreshToken cookie |
| POST | /api/auth/login | Verifies credentials against the User model |
| POST | /api/auth/refresh | Issues a new accessToken from the refresh cookie |
| POST | /api/auth/logout | Revokes the refresh token and clears the cookie |
Refresh tokens are stored as a SHA-256 hash, never in plain text. /auth/* routes are protected by a strict rate limiter (10 requests / 15 min); the rest of the API is protected by a general one (300 requests / 15 min).
Configure in .env:
JWT_SECRET=your-access-secret
JWT_EXPIRES_IN=15m
REFRESH_TOKEN_SECRET=your-refresh-secret
ALLOWED_ORIGINS=http://localhost:5173If you skip auth, none of src/modules/auth/, the auth routes, or the users/refresh_tokens migrations are generated.
API Documentation
Every generated project exposes interactive OpenAPI docs at:
GET /docsgenerate:model annotates the CRUD routes it creates automatically, so new modules show up in the docs without extra work.
Migrations
MySQL / PostgreSQL (Sequelize CLI)
# Run all pending migrations
npm run db:migrate
# Roll back the last migration
npm run db:migrate:undoMigration files are stored in db/migrations/ and tracked automatically by Sequelize CLI. If auth is enabled, users and refresh_tokens migrations are included from the start.
For local development, db/init.sql is mounted into the database container and runs automatically the first time docker compose up creates the volume — no need to run migrations just to get a working local DB.
SQL Server
# Run all pending .sql files (tracked in _migrations table)
npm run db:migrateDocker
# Start the full stack (app + database)
docker compose up
# Production build
docker compose up --build
# Detached mode
docker compose up -d- The
Dockerfileuses multi-stage builds: the production image contains only production dependencies and compiled source, and runs as a non-root user. - Database ports are published to
127.0.0.1only — never exposed to the network by default. MYSQL_ROOT_PASSWORD,MYSQL_PASSWORD,POSTGRES_PASSWORDandDB_PASSWORDhave no insecure defaults —docker compose upfails with a clear message if you haven't set them in.env.
Installed Dependencies
Production:
express dotenv cors helmet pino pino-http
bcryptjs jsonwebtoken zod express-rate-limit cookie-parser
swagger-jsdoc swagger-ui-express
+ DB driver (mongoose / mysql2+sequelize / pg+sequelize / mssql)Dev — runtime:
nodemon pino-pretty
+ TypeScript: ts-node typescript @types/*Dev — testing:
jest supertest eslint lint-staged
+ TypeScript: ts-jest @types/jest @types/supertest @typescript-eslint/parser @typescript-eslint/eslint-pluginDev — git hooks:
huskyDev — migrations:
sequelize-cli (MySQL / PostgreSQL only)All dependencies are installed with pinned version ranges (not floating latest) to avoid an unexpected major version breaking a freshly generated project.
Requirements
- Node.js >= 18.0.0
- npm >= 8.0.0
License
MIT © Felipe Vargas
