NestJS Template
The NestJS template provides a modern Node.js backend framework with TypeScript, perfect for building scalable server-side applications with excellent developer experience.
Technical Stack
- NestJS - Node.js framework
- TypeScript - Type-safe development
- Express - Web framework
- Docker - Containerization
- MariaDB - Database
- Redis - Caching
- Jest - Testing framework
Quick Start
1. Create Project
bash
# Initialize project
vup init my-api-project
cd my-api-project
# Add NestJS template
vup add my-api
2. Install Dependencies
bash
# Install dependencies
pnpm install
3. Start Development
bash
# Start development server
cd apps/my-api
pnpm dev
The API server will be available at http://localhost:3000
.
Project Structure
apps/my-api/
├── src/
│ ├── app.controller.ts # App controller
│ ├── app.module.ts # App module
│ ├── app.service.ts # App service
│ └── main.ts # Application entry point
├── test/
│ ├── app.e2e-spec.ts # E2E tests
│ └── jest-e2e.json # Jest E2E configuration
├── docker-compose.yml # Docker configuration
├── nest-cli.json # NestJS CLI configuration
├── package.json # Dependencies and scripts
└── tsconfig.json # TypeScript configuration
Core Features
Controller
typescript
// app.controller.ts
import { Controller, Get, Post, Body, Param } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
@Get(':id')
findOne(@Param('id') id: string): string {
return this.appService.findOne(id);
}
@Post()
create(@Body() createDto: any): string {
return this.appService.create(createDto);
}
}
Service
typescript
// app.service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
}
findOne(id: string): string {
return `Found item with id: ${id}`;
}
create(createDto: any): string {
return `Created item: ${JSON.stringify(createDto)}`;
}
}
Module
typescript
// app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Main Application
typescript
// main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Enable CORS
app.enableCors();
// Set global prefix
app.setGlobalPrefix('api');
await app.listen(3000);
console.log('Application is running on: http://localhost:3000');
}
bootstrap();
Development Tools
NestJS Configuration
json
// nest-cli.json
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"deleteOutDir": true
}
}
TypeScript Configuration
json
// tsconfig.json
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./dist",
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@shared/*": ["../../_shared/*"]
}
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "test", "**/*spec.ts"]
}
Docker Configuration
yaml
# docker-compose.yml
version: '3.8'
services:
api:
build: .
ports:
- '3000:3000'
environment:
- NODE_ENV=development
depends_on:
- mariadb
- redis
mariadb:
image: mariadb:10.9
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: myapp
MYSQL_USER: user
MYSQL_PASSWORD: password
ports:
- '3306:3306'
volumes:
- mariadb_data:/var/lib/mysql
redis:
image: redis:7-alpine
ports:
- '6379:6379'
volumes:
- redis_data:/data
volumes:
mariadb_data:
redis_data:
Available Scripts
json
{
"scripts": {
"dev": "nest start --watch",
"build": "nest build",
"start": "node dist/main",
"start:prod": "node dist/main",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json",
"lint": "eslint src/ --ext .ts",
"lint:fix": "eslint src/ --ext .ts --fix",
"format": "prettier --write \"src/**/*.{ts,json}\"",
"format:check": "prettier --check \"src/**/*.{ts,json}\""
}
}
Best Practices
Error Handling
typescript
import { HttpException, HttpStatus } from '@nestjs/common';
@Controller()
export class AppController {
@Get(':id')
findOne(@Param('id') id: string) {
if (!id || isNaN(Number(id))) {
throw new HttpException('Invalid ID', HttpStatus.BAD_REQUEST);
}
try {
return this.appService.findOne(id);
} catch (error) {
throw new HttpException('Item not found', HttpStatus.NOT_FOUND);
}
}
}
Validation
typescript
import { IsString, IsNotEmpty, IsOptional } from 'class-validator';
export class CreateItemDto {
@IsString()
@IsNotEmpty()
name: string;
@IsString()
@IsOptional()
description?: string;
}
@Controller()
export class AppController {
@Post()
create(@Body() createDto: CreateItemDto) {
return this.appService.create(createDto);
}
}
Database Integration
typescript
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Item } from './entities/item.entity';
@Injectable()
export class AppService {
constructor(
@InjectRepository(Item)
private itemRepository: Repository<Item>
) {}
async findAll(): Promise<Item[]> {
return this.itemRepository.find();
}
async findOne(id: number): Promise<Item> {
return this.itemRepository.findOne({ where: { id } });
}
async create(createDto: CreateItemDto): Promise<Item> {
const item = this.itemRepository.create(createDto);
return this.itemRepository.save(item);
}
}
Testing
Unit Tests
typescript
// app.service.spec.ts
import { Test, TestingModule } from '@nestjs/testing';
import { AppService } from './app.service';
describe('AppService', () => {
let service: AppService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [AppService],
}).compile();
service = module.get<AppService>(AppService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
it('should return "Hello World!"', () => {
expect(service.getHello()).toBe('Hello World!');
});
});
E2E Tests
typescript
// test/app.e2e-spec.ts
import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import * as request from 'supertest';
import { AppModule } from './../src/app.module';
describe('AppController (e2e)', () => {
let app: INestApplication;
beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = moduleFixture.createNestApplication();
await app.init();
});
it('/ (GET)', () => {
return request(app.getHttpServer())
.get('/')
.expect(200)
.expect('Hello World!');
});
});
Deployment
Build for Production
bash
# Build the application
pnpm build
# The built files will be in the dist directory
Docker Deployment
bash
# Build Docker image
docker build -t my-api .
# Run with Docker Compose
docker-compose up -d