NestJS Microservices


nself provides comprehensive support for NestJS microservices, enabling you to build scalable, modular backend services that integrate seamlessly with your nself stack. With built-in 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 templates and generators
  • 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

Enable NestJS Services

Add NestJS services to your .env.local:

# Enable NestJS microservices
NESTJS_SERVICES=api,webhooks,auth-service

# Optional: Specify NestJS version
NESTJS_VERSION=10.x

# Optional: Enable additional features
NESTJS_SWAGGER=true
NESTJS_VALIDATION=true
NESTJS_CACHE=true

Generate Service Structure

# Generate NestJS services
nself build

# Start services
nself up

This creates the following structure:

services/
├── nestjs/
│   ├── api/                 # Main API service
│   │   ├── src/
│   │   ├── Dockerfile
│   │   ├── package.json
│   │   └── tsconfig.json
│   ├── webhooks/           # Webhook handler service
│   └── auth-service/       # Authentication microservice
└── shared/
    └── types/              # Shared TypeScript types

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 specific services
NESTJS_API_REPLICAS=3
NESTJS_WEBHOOKS_REPLICAS=2
NESTJS_AUTH_REPLICAS=2

# Configure in .env.local and rebuild
nself build && nself restart

CLI Commands

Service Management

# Generate new NestJS service
nself generate nestjs --name user-service

# Add new module to existing service
nself generate nestjs:module --service api --name payments

# Add controller
nself generate nestjs:controller --service api --name users

# Add service provider
nself generate nestjs:service --service api --name users

Development Tools

# Watch mode for development
nself dev nestjs --service api

# Run tests
nself test nestjs --service api

# View service logs
nself logs nestjs --service api --follow

# Execute commands in service
nself exec nestjs api npm run migration:generate

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.