NestJs Backend Starter - RemalDev
Up-to-date NestJS-based API boilerplate with Prisma ORM, authentication, and testing setup.
- Setup
- Database Commands
- Development Commands
- Testing Commands
- Git Workflow Commands
- Project Structure
Prerequisites: Volta, Node.js (v24.13.0), npm (v11.6.2), PostgreSQL
-
Create a new repository from template:
Go to the backend-template repository and click "Use this template" to create your own repository based on this template.
Then clone your new repository:
git clone https://github.com/your-username/your-repo-name.git && cd your-repo-name && npm install
-
Environment setup:
Copy the
.env.examplefile to create your own.envfile:cp .env.example .env
Then update the values in your
.envfile as needed:# Database connection strings DB_POSTGRE_URI="postgresql://iam_username:iam_psswd@localhost:3033/remal_db?schema=public" DB_MONGO_URI="mongodb://iam_username:iam_psswd@localhost:3044/remal_db" # Environment name (local, dev, test, prod) NODE_ENV=local # Application settings PORT=3000 LOG_LEVEL=log HOST=127.0.0.1
For different environments, you can create specific env files:
.env.local- Local development.env.test- Testing environment (used by Jest).env.dev- Development server.env.prod- Production environment
Environment variables are loaded based on NODE_ENV value, with values from the specific environment file taking precedence over the base
.envfile. -
Setup database:
npm run prisma:migrate:deploy
-
Start development server:
npm run start:dev # API runs at http://localhost:3000
The application includes a comprehensive JWT-based authentication system with email verification:
| Endpoint | Method | Description | Body | Response |
|---|---|---|---|---|
/auth/signup |
POST | Register new user with email verification | { email, password, firstName, lastName } |
{ message, user } |
/auth/login |
POST | Login with JWT tokens | { email, password } |
{ accessToken, refreshToken, user } |
/auth/verify/:token |
GET | Verify email with 6-digit code | - | { message, user } |
/auth/protected/user |
GET | User-protected route (requires JWT) | - | { message, user } |
/auth/protected/admin |
GET | Admin-protected route (requires admin role) | - | { message, user } |
/user/profile |
GET | Get current user profile | - | { user } |
- JWT Tokens: Access tokens with refresh token rotation
- Email Verification: 6-digit verification codes sent via email
- Role-based Access: User and Admin role protection
- Password Security: bcrypt hashing with salt rounds
- Token Management: Automatic token refresh and blacklisting
The project includes comprehensive Bruno API collections in bruno/remal-api-1/ for testing all authentication endpoints:
auth/signup.bru- User registrationauth/login.bru- User loginauth/verifyToken.bru- Email verificationauth/protected_path_user.bru- User-protected routesauth/protected_path_admin.bru- Admin-protected routesuser/my_profile.bru- User profile management
| Command | Description |
|---|---|
npm run prisma:generate |
Generate Prisma client after schema changes |
npm run prisma:migrate |
Create a new migration when schema.prisma is modified |
npm run prisma:migrate:deploy |
Apply pending migrations (run after pulling new changes with migrations) |
npm run prisma:migrate:reset |
Reset database ( |
npm run prisma:seed |
Populate database with initial data |
npm run prisma:studio |
Open Prisma Studio to explore database |
| Command | Description |
|---|---|
npm run start:dev |
Start development server with hot-reload |
npm run lint |
Run ESLint to check code quality |
npm run format |
Format code with Prettier |
npm run deps:outdated:check |
Check for outdated dependencies |
bash update-packages.sh |
Update dependencies safely + Auto-commit |
npm run build |
Build application for production |
| Command | Description |
|---|---|
npm test |
Run all unit tests |
npm run test:watch |
Run tests in watch mode |
npm run test:cov |
Generate test coverage report |
npm run test:e2e |
Run end-to-end tests |
| Command | Description |
|---|---|
git checkout -b feature/R-123 |
Create new feature branch (use ticket number) |
git add file1 file2 |
Stage target changes |
git commit -m "feat(user): add createUser controller" |
Commit with conventional format |
git push origin feature/R-123 |
Push changes to remote |
| Command | Description |
|---|---|
git checkout -b feature/R-123 |
Create new feature branch (use ticket number) |
git add src/module/dto/*.dto.ts && git commit -m "feat(module): add data transfer objects" |
Commit DTOs |
git add src/module/module.service.ts && git commit -m "feat(module): implement core service logic" |
Commit service changes |
git add src/module/module.controller.ts && git commit -m "feat(module): add controller endpoints" |
Commit controller changes |
git add src/module/*.spec.ts && git commit -m "test(module): add unit tests" |
Commit unit tests |
git add test/module.e2e-spec.ts && git commit -m "test(module): add e2e tests" |
Commit e2e tests |
git add src/module/module.controller.ts && git commit -m "doc(module): add swagger documentation to endpoints" |
Commit documentation updates to controller |
git add bruno/remal-api-1/user/create-module.bru && git commit -m "doc(module): add bruno collection of endpoints" |
Commit bruno collections used to test |
git add src/app.module.ts && git commit -m "feat(app): register module module" |
Commit module registration |
git push origin feature/R-123 |
Push all commits to remote |
Allowed Types: feat, fix, test, docs, refact, build, ci, chore, perf, revert, style
Commit Convention with Commitlint
This project enforces conventional commit messages using Commitlint. All commits must follow this format:
# Format: type(scope): description
git commit -m "feat(auth): add JWT refresh token rotation"
git commit -m "fix(user): handle edge case in profile update"
git commit -m "test(auth): add e2e tests for signup flow"
git commit -m "docs(readme): update authentication section"| Command | Description |
|---|---|
git pull origin main |
Pull latest changes from main branch |
git fetch --all |
Fetch all branches from remote |
git stash |
Temporarily save changes to work on something else |
git stash list |
List all stashed changes |
git stash apply stash@{n} |
Apply stash number n without removing it |
git stash pop stash@{n} |
Apply and remove stash number n |
git reset --soft HEAD~1 |
Undo last commit, keep changes staged |
git reset --hard HEAD~1 |
|
git checkout - |
Switch to previous branch |
When main branch has been updated and you need to update your feature branch:
# If you haven't pushed your changes yet:
git checkout main
git pull
git checkout feature/R-123
git rebase main
# If you've already pushed your feature branch:
git checkout main
git pull
git checkout feature/R-123
git rebase main
git push origin feature/R-123 --force-with-lease # ⚠️ Use with caution.
├── .github/ # GitHub Actions workflows and scripts
│ ├── workflows/ # CI/CD pipeline definitions
│ └── scripts/ # Helper scripts for CI/CD
├── bruno/ # Bruno API collections for testing
│ └── remal-api-1/ # Organized by modules/features
├── prisma/ # Database configuration
│ ├── migrations/ # Database migrations
│ ├── schema.prisma # Database schema
│ └── prisma.seed.ts # Seed data
├── src/
│ ├── common/ # Shared utilities, filters, exceptions
│ │ ├── dto/ # Common DTOs
│ │ ├── exceptions/ # Custom exceptions
│ │ └── filters/ # Exception filters
│ ├── config/ # Application configuration
│ │ └── configuration.ts # Environment configuration
│ ├── auth/ # Authentication module
│ │ ├── dto/ # Auth DTOs (signup, login, etc.)
│ │ ├── guards/ # JWT guards and role guards
│ │ ├── auth.controller.ts # Auth endpoints
│ │ ├── auth.module.ts # Auth module definition
│ │ ├── auth.service.ts # Auth business logic
│ │ ├── jwt.strategy.ts # JWT validation strategy
│ │ └── *.spec.ts # Unit tests
│ ├── mailer/ # Email service module
│ │ ├── templates/ # Email templates
│ │ ├── mailer.service.ts # Email sending logic
│ │ └── mailer.module.ts # Mailer module definition
│ ├── prisma/ # Database module, service
│ ├── user/ # User module (profile management)
│ │ ├── dto/ # Data transfer objects
│ │ ├── entities/ # Domain entities
│ │ ├── utils/ # Helper functions
│ │ ├── user.controller.ts # REST endpoints
│ │ ├── user.module.ts # Module definition
│ │ ├── user.service.ts # Business logic
│ │ └── *.spec.ts # Unit tests
│ ├── app.bootstrap.ts # Application bootstrap configuration
│ ├── app.controller.ts # Root controller (health check)
│ ├── app.module.ts # Root module
│ └── main.ts # Application entry point
├── test/
│ ├── e2e/ # End-to-end tests
│ ├── helpers/ # Test utilities
│ ├── global.d.ts # TypeScript declarations for tests
│ ├── jest-global-setup.ts # Jest setup
│ ├── jest-global-teardown.ts # Jest teardown
│ ├── jest-setup.ts # Test application setup
│ └── jest.config.ts # Jest configuration
├── .env.example # Environment variables template
├── .env.local # Local environment variables (gitignored)
├── .env.test # Test environment variables
├── .env.dev # Development environment variables (optional)
├── .env.prod # Production environment variables (optional)
└── package.json # Project metadata and scripts
Includes GitHub Actions workflows for:
- Code quality checks (linting, formatting)
- Test coverage reporting (minimum 85% threshold)
- Dependency analysis
The project uses a hierarchical environment loading system that allows for environment-specific configurations:
.env- Base environment file with common settings.env.local- Local development overrides (gitignored).env.test- Testing environment settings.env.dev- Development server settings.env.prod- Production environment settings
- The base
.envfile is always loaded first - Then, based on the
NODE_ENVvalue, a specific environment file (.env.local,.env.test, etc.) is loaded - Values from the environment-specific file override those from the base
.envfile
Environment variables are loaded in main.ts and are available throughout the application via NestJS's ConfigService:
// Example of using environment variables in a service
import { Injectable } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
@Injectable()
export class MyService {
constructor(private configService: ConfigService) {}
someMethod() {
const port = this.configService.get<number>("PORT");
const dbUri = this.configService.get<string>("DB_POSTGRE_URI");
// ...
}
}The project includes several tools to improve development workflow and code quality:
| Tool | Purpose | Configuration |
|---|---|---|
| Biome | Modern formatter and linter | .biome.json |
| Commitlint | Enforce consistent commit message format | commitlint.config.ts |
| Husky | Git hooks for pre-commit validation | .husky/ |
| Lint-staged | Run linters on staged files before committing | package.json > "lint-staged" |
| Tool | Purpose | Configuration |
|---|---|---|
| Jest | Testing framework | test/jest.config.ts |
| Supertest | HTTP assertions for API testing | Used in e2e tests |
| Testcontainers | Disposable Docker containers for tests | Used in jest-global-setup.ts |
| Bruno | API client for endpoint testing | bruno/ directory |
| Command | Description |
|---|---|
npm run deps:check |
Check for unused dependencies |
npm run deps:outdated:check |
Check for outdated packages |
npm run deps:update:all |
Update all dependencies at once |
bash update-packages.sh |
Safely update dependencies one by one with commits |
The project follows these security best practices:
- Uses class-validator for input validation
- Implements rate limiting for sensitive endpoints
- All API endpoints are documented and versioned
- Properly handles and sanitizes error messages
- Environment variables for sensitive information
- Different environment configurations for development and production
- Using parameterized queries with Prisma ORM to prevent SQL injection
- Strong password hashing with bcrypt
- Automated dependency scanning in CI pipeline
- Regular updates of all dependencies
- Minimum test coverage requirements
- Secrets stored in GitHub Actions secrets, not in code
- Never commit
.envfiles with real credentials - Use
.env.exampleas a template with placeholder values - Run
npm auditregularly to check for vulnerabilities - Keep dependencies updated using the provided scripts