NestJS Microservices

v0.4.8

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.

Overview

NestJS is a progressive Node.js framework for building efficient and scalable server-side applications. When combined with nself, you get:

Key Benefits

  • Rapid Development: Pre-configured nest-js and nest-ts templates
  • Seamless Integration: Automatic connection to PostgreSQL, Redis, and other nself services
  • Microservices Architecture: Built-in support for distributed systems patterns
  • Type Safety: Full TypeScript support with shared types
  • Production Ready: Docker containers, health checks, and monitoring

Supported Patterns

  • REST APIs: Traditional HTTP-based services
  • GraphQL APIs: Integration with Hasura or standalone
  • Message Queues: Integration with BullMQ and Redis
  • Microservices: Inter-service communication patterns
  • CRON Jobs: Scheduled tasks and background processing

Getting Started

Custom Service Configuration

Add 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 Service Structure

# Generate NestJS services from templates
nself build

# Start all services
nself start

This 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.json

Service Templates

REST API Service

Basic 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 {}

GraphQL Integration

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 {}

Message Queue Integration

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 {}

Database Integration

TypeORM Configuration

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 {}

Entity Example

// 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;
}

Advanced Features

Authentication Integration

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;
    }
  }
}

Health Checks

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'),
    ]);
  }
}

Logging and Monitoring

// 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`);
      }),
    );
  }
}

Deployment and Scaling

Docker Configuration

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"]

Horizontal Scaling

# 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

CLI Commands

Service Management

# 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

Development Tools

# 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 status

Best Practices

Architecture Patterns

  • Single Responsibility: Each service handles one domain
  • Database Per Service: Use schema separation or separate databases
  • API Gateway Pattern: Use one service as the main API gateway
  • Event-Driven Communication: Use BullMQ for async service communication

Development Workflow

  1. Schema First: Design your database schema first
  2. Generate Entities: Create TypeORM entities from schema
  3. Build Services: Implement business logic in services
  4. Add Controllers: Create API endpoints
  5. Write Tests: Add unit and integration tests
  6. Deploy: Use nself for production deployment

Next Steps

Now that you understand NestJS microservices:

NestJS services provide a robust, scalable foundation for building enterprise-grade applications with nself.