A production-ready NestJS backend template with TypeORM (MySQL), ESLint (Airbnb rules), Husky, Swagger, and a fully working example module.
- Framework: NestJS v11
- Database: MySQL via TypeORM (Query Builder)
- Validation: class-validator + class-transformer
- API Docs: Swagger / OpenAPI
- Linting: ESLint with Airbnb ruleset + Prettier
- Git Hooks: Husky (pre-commit: format → lint → test)
src/
├── common/
│ ├── constants.ts # App-wide constants
│ ├── db/
│ │ ├── datasource.ts # TypeORM DataSource config
│ │ └── entities/
│ │ └── example.user.entity.ts
│ └── utils/
│ └── isMySqlError.ts # MySQL error type guard
├── migrations/
│ └── <timestamp>-Init.ts # Generated migrations go here
├── modules/
│ └── example-user/ # ← Use this as a module template
│ ├── dto/
│ │ ├── createExampleUser.dto.ts
│ │ └── returnExampleUser.dto.ts
│ ├── example.user.constants.ts
│ ├── example.user.controller.ts
│ ├── example.user.module.ts
│ └── example.user.service.ts
├── app.controller.ts
├── app.module.ts
├── app.service.ts
└── main.ts
The example-user module demonstrates the standard pattern for all modules:
| File | Purpose |
|---|---|
*.module.ts |
Registers entity, service, exports |
*.controller.ts |
Route handlers + Swagger decorators |
*.service.ts |
Business logic using Query Builder |
dto/create*.dto.ts |
Request body validation |
dto/return*.dto.ts |
Response shape (with @Expose()) |
npm installcp .env.example .envEdit .env with your MySQL credentials:
PORT=3000
NODE_ENV=development
DB_TYPE=mysql
DB_HOST=localhost
DB_PORT=3306
DB_USERNAME=root
DB_PASSWORD=your_password
DB_NAME=red_an_be_dbnpm run migration:run# development (watch mode)
npm run start:dev
# production
npm run start:prodhttp://localhost:3000/api
This project uses TypeORM with Query Builder — no .find() / .save() shortcuts.
All DB operations go through createQueryBuilder(). Example from example.user.service.ts:
// SELECT
const users = await this.userRepository.createQueryBuilder('templateUser').getMany();
// INSERT
await this.userRepository
.createQueryBuilder()
.insert()
.into(TemplateUser)
.values([{ email }])
.execute();# Generate a new migration (auto-diffs entities vs DB)
npm run migration:generate src/migrations/<MigrationName>
# Apply pending migrations
npm run migration:run
# Revert last migration
npm run migration:revert
# Show migration status
npm run migration:showWarning:
synchronizeis set tofalse— always use migrations.
ESLint is configured with the Airbnb ruleset + TypeScript + Prettier.
# Lint and auto-fix
npm run lint
# Format with Prettier
npm run formatKey rules (.eslintrc.js):
airbnb-base+airbnb-typescript/base@typescript-eslint/no-explicit-any→ error@typescript-eslint/no-floating-promises→ warnprettier/prettier→ error
A pre-commit hook runs automatically before every commit:
npm run format && npm run lint && npm testIf any step fails, the commit is blocked.
To install hooks after cloning:
npm install # automatically runs `husky` via `prepare` script# Unit tests
npm run test
# Watch mode
npm run test:watch
# Coverage report
npm run test:cov
# E2E tests
npm run test:e2eFollow the example-user pattern:
- Create folder:
src/modules/<your-module>/ - Add
dto/,*.entity.tsincommon/db/entities/ - Create
*.module.ts,*.controller.ts,*.service.ts - Register entity in
datasource.ts→entities: [...] - Import your module in
app.module.ts - Generate a migration:
npm run migration:generate src/migrations/<name>