Skip to main content

Type-safe RPC for NestJS

Call Nest methods like local functions. Zero boilerplate. End-to-end types.

🔗

Nest-native

Routers are just classes. Methods are just Nest handlers, discovered via decorators.

🧠

Type-safe

Input types flow from server to client. Call methods with full IntelliSense.

âš¡

Zero boilerplate

Define once with @Router and @Route. Use everywhere via RpcClient.

Server · Router

server/app.router.ts
import { Module } from '@nestjs/common';
import { Router, Route, defineManifest } from '@nestjs-rpc/server';

@Router()
export class UsersRouter {
@Route()
getUser({ id }: { id: string }) {
return { id, name: 'Ada Lovelace' };
}
}

export const manifest = defineManifest({
users: UsersRouter,
});

export type Manifest = typeof manifest;

@Module({ controllers: [UsersRouter] })
export class AppModule {}

Client · Typed usage

client/rpc.ts
import { RpcClient } from '@nestjs-rpc/client';
import type { Manifest } from '../server/nest-rpc.config';

const client = new RpcClient<Manifest>({
baseUrl: 'https://api.example.com',
apiPrefix: 'nestjs-rpc',
});

const rpc = client.routers();
const { data: user } = await rpc.users.getUser({ id: '1' });
console.log(user.name); // "Ada Lovelace"

// Router constants
export const userRepo = client.route('users');

// Calls
const { data: one } = await userRepo.getUser({ id: '1' });


How it works

  1. Define routers with @Router() and methods with @Route().
  2. Declare a manifest with defineManifest(...) and export type Manifest.
  3. Init with nestRpcInit(manifest) inside the bootstrap() { ... }, then call from the client via RpcClient.