Updated for nself v0.4.8
nself provides comprehensive support for NestJS microservices through custom service templates, enabling you to build scalable, modular backend services that integrate seamlessly with your nself stack. With the nest-js and nest-ts templates, automatic configuration, and production-ready deployment, you can focus on building features while nself handles the infrastructure.
NestJS is a progressive Node.js framework for building efficient and scalable server-side applications. When combined with nself, you get:
nest-js and nest-ts templatesAdd NestJS services using the custom service (CS_N) format in your .env file:
# Custom Service Format: CS_N=name:template:port:route
# Available NestJS templates: nest-js, nest-ts
# NestJS API with TypeScript (recommended)
CS_1=api:nest-ts:3001:/api
# NestJS webhook handler
CS_2=webhooks:nest-ts:3002:/webhooks
# NestJS auth microservice
CS_3=auth-service:nest-ts:3003:/auth# Generate NestJS services from templates
nself build
# Start all services
nself startThis creates the following structure:
services/
├── api/ # Main API service (nest-ts)
│ ├── src/
│ ├── Dockerfile
│ ├── package.json
│ └── tsconfig.json
├── webhooks/ # Webhook handler service (nest-ts)
│ ├── src/
│ ├── Dockerfile
│ └── package.json
└── auth-service/ # Authentication microservice (nest-ts)
├── src/
├── Dockerfile
└── package.jsonBasic REST API with database integration:
// src/app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigModule } from '@nestjs/config';
import { UsersModule } from './users/users.module';
@Module({
imports: [
ConfigModule.forRoot(),
TypeOrmModule.forRoot({
type: 'postgres',
host: process.env.POSTGRES_HOST,
port: parseInt(process.env.POSTGRES_PORT),
username: process.env.POSTGRES_USER,
password: process.env.POSTGRES_PASSWORD,
database: process.env.POSTGRES_DB,
autoLoadEntities: true,
synchronize: false, // Use nself migrations instead
}),
UsersModule,
],
})
export class AppModule {}Integration with Hasura GraphQL:
// src/graphql/graphql.module.ts
import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';
import { ApolloDriverConfig, ApolloDriver } from '@nestjs/apollo';
@Module({
imports: [
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
autoSchemaFile: 'schema.gql',
context: ({ req }) => ({ req }),
introspection: true,
playground: true,
}),
],
})
export class GraphQLAppModule {}BullMQ integration for background jobs:
// src/jobs/jobs.module.ts
import { Module } from '@nestjs/common';
import { BullModule } from '@nestjs/bull';
import { EmailProcessor } from './processors/email.processor';
@Module({
imports: [
BullModule.forRoot({
redis: {
host: process.env.REDIS_HOST,
port: parseInt(process.env.REDIS_PORT),
},
}),
BullModule.registerQueue({
name: 'email',
}),
],
providers: [EmailProcessor],
})
export class JobsModule {}Pre-configured TypeORM setup with nself database:
// src/database/database.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigService } from '@nestjs/config';
@Module({
imports: [
TypeOrmModule.forRootAsync({
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
type: 'postgres',
host: config.get('POSTGRES_HOST'),
port: config.get('POSTGRES_PORT'),
username: config.get('POSTGRES_USER'),
password: config.get('POSTGRES_PASSWORD'),
database: config.get('POSTGRES_DB'),
entities: [__dirname + '/../**/*.entity{.ts,.js}'],
synchronize: false,
logging: config.get('NODE_ENV') === 'development',
ssl: config.get('NODE_ENV') === 'production' ? { rejectUnauthorized: false } : false,
}),
}),
],
})
export class DatabaseModule {}// src/users/entities/user.entity.ts
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm';
@Entity('users')
export class User {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column({ unique: true })
email: string;
@Column()
password_hash: string;
@Column({ nullable: true })
first_name: string;
@Column({ nullable: true })
last_name: string;
@Column({ default: true })
is_active: boolean;
@CreateDateColumn()
created_at: Date;
@UpdateDateColumn()
updated_at: Date;
}JWT authentication with nself's auth service:
// src/auth/auth.guard.ts
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private jwtService: JwtService) {}
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest();
const token = request.headers.authorization?.split(' ')[1];
if (!token) return false;
try {
const payload = this.jwtService.verify(token);
request.user = payload;
return true;
} catch {
return false;
}
}
}Automatic health check endpoints:
// src/health/health.controller.ts
import { Controller, Get } from '@nestjs/common';
import { HealthCheckService, HealthCheck, TypeOrmHealthIndicator } from '@nestjs/terminus';
@Controller('health')
export class HealthController {
constructor(
private health: HealthCheckService,
private db: TypeOrmHealthIndicator,
) {}
@Get()
@HealthCheck()
check() {
return this.health.check([
() => this.db.pingCheck('database'),
]);
}
}// src/common/interceptors/logging.interceptor.ts
import { Injectable, NestInterceptor, ExecutionContext, CallHandler, Logger } from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
private readonly logger = new Logger(LoggingInterceptor.name);
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const request = context.switchToHttp().getRequest();
const method = request.method;
const url = request.url;
const now = Date.now();
return next.handle().pipe(
tap(() => {
const response = context.switchToHttp().getResponse();
const statusCode = response.statusCode;
const delay = Date.now() - now;
this.logger.log(`${method} ${url} ${statusCode} - ${delay}ms`);
}),
);
}
}Each NestJS service gets optimized Docker configuration:
# Dockerfile (auto-generated)
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
FROM node:18-alpine AS runtime
WORKDIR /app
# Create non-root user
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nestjs -u 1001
# Copy built application
COPY --from=builder --chown=nestjs:nodejs /app/node_modules ./node_modules
COPY --chown=nestjs:nodejs . .
USER nestjs
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
CMD ["npm", "run", "start:prod"]# Scale services using multiple CS_N entries
CS_1=api-1:nest-ts:3001:/api
CS_2=api-2:nest-ts:3002:/api
CS_3=api-3:nest-ts:3003:/api
# Or use Docker Compose deploy configuration
# Configure in .env and rebuild
nself build && nself restart# Add a NestJS service via CS_N configuration
# In .env file:
CS_1=user-service:nest-ts:3001:/users
# Rebuild to generate from template
nself build
# Start services
nself start# View service logs
nself logs api
# Follow logs in real-time
nself logs api -f
# Execute commands in service container
nself exec api npm run migration:generate
# Check service status
nself statusNow that you understand NestJS microservices:
NestJS services provide a robust, scalable foundation for building enterprise-grade applications with nself.