Nest Integration
Proper integration with NestJS requires calling nestRpcInit() before app creation and properly defining your manifest. This guide covers the essential setup steps.
⚠️ Critical: Initialize Before App Creation
nestRpcInit() MUST be called BEFORE NestFactory.create(). This is essential because NestRPC applies NestJS decorators (@Controller(), @Post(), etc.) to your router classes, and NestJS needs these decorators to be present when it discovers controllers during app creation.
// main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { nestRpcInit } from '@nestjs-rpc/server';
import { manifest } from './nest-rpc.config';
async function bootstrap() {
// ✅ Must be called BEFORE app creation
// This applies decorators that Nest needs at bootstrap
nestRpcInit(manifest, { apiPrefix: 'nestjs-rpc' }); // 'nestjs-rpc' is default
// Then create your Nest app
const app = await NestFactory.create(AppModule);
// Enable CORS if needed for your client
app.enableCors({
origin: 'http://localhost:5173',
credentials: true,
});
await app.listen(3000);
console.log('🚀 Server running on http://localhost:3000');
}
bootstrap();
Why This Order Matters
nestRpcInit()applies decorators to your router classesNestFactory.create()discovers controllers by scanning for@Controller()decorators- If
nestRpcInit()is called afterNestFactory.create(), the decorators won't be applied in time - Your routes won't be registered
📋 Define the Manifest
defineManifest() creates a manifest from your router structure and preserves type information so the client can infer method signatures and inputs.
// nest-rpc.config.ts
import { defineManifest } from '@nestjs-rpc/server';
import { UserQueriesRouter } from './user/user.queries.router';
import { UserMutationsRouter } from './user/user.mutations.router';
import { FilesRouter } from './files/files.router';
export const manifest = defineManifest({
user: {
queries: UserQueriesRouter,
mutations: UserMutationsRouter,
},
files: FilesRouter,
});
// 🔁 Always export the type for client-side type safety
export type Manifest = typeof manifest;
Manifest Structure
The manifest structure defines your API organization:
export const manifest = defineManifest({
// Flat structure
user: UserRouter,
files: FilesRouter,
// Nested structure
admin: {
users: AdminUsersRouter,
settings: AdminSettingsRouter,
},
});
The keys you choose become the paths on the client:
rpc.user.someMethod()rpc.files.uploadFile()rpc.admin.users.listAll()
📦 Register Routers in Module
⚠️ CRITICAL: Routers are NestJS controllers under the hood. Router classes MUST be registered in your NestJS module's controllers array for them to work:
// app.module.ts
import { Module } from '@nestjs/common';
import { UserQueriesRouter } from './user/user.queries.router';
import { UserMutationsRouter } from './user/user.mutations.router';
import { FilesRouter } from './files/files.router';
@Module({
controllers: [
UserQueriesRouter,
UserMutationsRouter,
FilesRouter,
],
providers: [],
})
export class AppModule {}
🔧 Configuration Options
API Prefix
Set a custom API prefix:
nestRpcInit(manifest, { apiPrefix: 'api/v1' });
All routes will be prefixed with this path:
POST /api/v1/user/getUserByIdPOST /api/v1/files/uploadFile
Default: 'nestjs-rpc'
✅ Complete Setup Example
Here's a complete setup example:
// nest-rpc.config.ts
import { defineManifest } from '@nestjs-rpc/server';
import { UserQueriesRouter } from './user/user.queries.router';
import { UserMutationsRouter } from './user/user.mutations.router';
export const manifest = defineManifest({
user: {
queries: UserQueriesRouter,
mutations: UserMutationsRouter,
},
});
export type Manifest = typeof manifest;
// app.module.ts
import { Module } from '@nestjs/common';
import { UserQueriesRouter } from './user/user.queries.router';
import { UserMutationsRouter } from './user/user.mutations.router';
@Module({
controllers: [UserQueriesRouter, UserMutationsRouter],
providers: [],
})
export class AppModule {}
// main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { nestRpcInit } from '@nestjs-rpc/server';
import { manifest } from './nest-rpc.config';
async function bootstrap() {
// ✅ Step 1: Initialize RPC (MUST be first)
nestRpcInit(manifest, { apiPrefix: 'nestjs-rpc' });
// ✅ Step 2: Create Nest app
const app = await NestFactory.create(AppModule);
// ✅ Step 3: Configure app (CORS, etc.)
app.enableCors({
origin: 'http://localhost:5173',
credentials: true,
});
// ✅ Step 4: Start server
await app.listen(3000);
console.log('🚀 Server running on http://localhost:3000');
}
bootstrap();
🐛 Troubleshooting
Routes Not Registered
If your routes aren't being registered:
- ✅ Check that
nestRpcInit()is called beforeNestFactory.create() - ✅ Check that router classes are in the module's
controllersarray - ✅ Check that classes have
@Router()decorator - ✅ Check that methods have
@Route()decorator
Type Errors
If you're getting type errors:
- ✅ Make sure you export
export type Manifest = typeof manifest - ✅ Make sure the client imports the correct
Manifesttype - ✅ Check that TypeScript can resolve the type (may need path mapping)
📚 Further Reading
- Quick Start - Get started quickly
- Routers and Routes - Define routes
- Execution Context - How routes execute