npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@nestjs-rpc/client

v2.1.7

Published

<div align="center">

Readme

@nestjs-rpc/client

Type-safe RPC client for calling NestJS methods from any frontend. Full TypeScript inference, zero configuration.

npm version npm downloads License: MIT TypeScript

InstallationQuick StartExamples


📖 📚 Full Documentation → 📖

Complete guides, API reference, and advanced examples


🎯 Why @nestjs-rpc/client?

Stop writing API client wrappers manually. This package gives you:

  • 🔒 End-to-End Type Safety - Import your server's manifest type for complete type inference
  • 🎯 Zero Boilerplate - No manual API wrappers or type definitions
  • 📤 Built-in File Uploads - Upload files with simple { file } or { files: [] } options
  • Proxy-Based API - Call methods like rpc.user.getUserById('123') - feels like local functions
  • 🎨 Framework Agnostic - Works with React, Vue, Angular, Svelte, or vanilla JS
  • 🔧 Fully Customizable - Built on Axios with full configuration support

The Traditional Way (Without NestRPC)

// ❌ Manual API client with no type safety
const response = await fetch('/api/user/getUserById', {
  method: 'POST',
  body: JSON.stringify({ id: '123' }),
});
const user = await response.json(); // 😱 No types!

The NestRPC Way

// ✅ Type-safe, feels like a local function
const { data: user } = await rpc.user.getUserById('123');
//    ^? { id: string; name: string; email: string }
// Full autocomplete and type checking! 🎉

📦 Installation

npm install @nestjs-rpc/client axios
# or
pnpm add @nestjs-rpc/client axios
# or
yarn add @nestjs-rpc/client axios

Peer Dependencies:

  • axios - Used as the default HTTP client (you can provide your own)

🚀 Quick Start

1. Import Your Server's Manifest Type

First, make sure your server exports the manifest type:

// server/src/nest-rpc.config.ts
export const manifest = defineManifest({ /* ... */ });
export type Manifest = typeof manifest; // 👈 Export this!

2. Create the Client

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

export const rpcClient = new RpcClient<Manifest>({
  baseUrl: 'http://localhost:3000',
  apiPrefix: 'nestjs-rpc', // Optional, defaults to 'nestjs-rpc'
});

export const rpc = rpcClient.routers();

3. Use with Full Type Safety!

// Now you have full type safety and autocomplete!
const { data: user } = await rpc.user.getUserById('123');
//    ^? { id: string; name: string; email: string }

await rpc.user.createUser({ 
  name: 'Jane Doe', 
  email: '[email protected]' 
});

const { data: users } = await rpc.user.listUsers();
//    ^? Array<{ id: string; name: string; email: string }>

That's it! You get:

  • ✅ Full TypeScript autocomplete
  • ✅ Compile-time type checking
  • ✅ Runtime type safety
  • ✅ Zero boilerplate

📤 File Uploads

NestRPC client has built-in support for file uploads. No FormData handling needed!

Single File Upload

const fileInput = document.querySelector<HTMLInputElement>('input[type="file"]');

const { data } = await rpc.user.uploadAvatar(
  { userId: '123' },
  { file: fileInput.files[0] }
);

Multiple File Upload

const fileInput = document.querySelector<HTMLInputElement>('input[type="file"]');

const { data } = await rpc.files.uploadDocuments(
  { category: 'invoices' },
  { files: Array.from(fileInput.files) }
);

With React Example

function FileUpload() {
  const [file, setFile] = useState<File | null>(null);

  const handleUpload = async () => {
    if (!file) return;
    
    const { data } = await rpc.user.uploadAvatar(
      { userId: '123' },
      { file }
    );
    
    console.log('Uploaded:', data);
  };

  return (
    <div>
      <input 
        type="file" 
        onChange={(e) => setFile(e.target.files?.[0] || null)} 
      />
      <button onClick={handleUpload}>Upload</button>
    </div>
  );
}

🔧 Configuration

Basic Configuration

const rpcClient = new RpcClient<Manifest>({
  baseUrl: 'http://localhost:3000',
  apiPrefix: 'nestjs-rpc', // Optional
});

Advanced Configuration

import axios from 'axios';

// Create custom Axios instance
const axiosInstance = axios.create({
  timeout: 10000,
  headers: {
    'X-Custom-Header': 'value',
  },
});

const rpcClient = new RpcClient<Manifest>({
  baseUrl: 'http://localhost:3000',
  apiPrefix: 'nestjs-rpc',
  axiosInstance, // Use custom instance
  requestOptions: {
    // Default options for all requests
    headers: {
      Authorization: 'Bearer token',
    },
  },
});

Per-Call Options

Override options for individual calls:

// Add custom headers for this call
const { data } = await rpc.user.getUserById('123', {
  requestOptions: {
    headers: {
      Authorization: 'Bearer custom-token',
      'X-Custom-Header': 'value',
    },
  },
});

// Use different Axios instance for this call
const { data } = await rpc.user.getUserById('123', {
  axiosInstance: customAxiosInstance,
});

Dynamic Configuration

Update configuration at runtime:

// Update base URL
rpcClient.$setConfigProperty('baseUrl', 'https://api.production.com');

// Or update entire config
rpcClient.$setConfig({
  baseUrl: 'https://api.production.com',
  requestOptions: {
    headers: {
      Authorization: `Bearer ${newToken}`,
    },
  },
});

// Read current config
const config = rpcClient.$config;
console.log(config.baseUrl);

🎨 Framework Examples

React

import { useState, useEffect } from 'react';
import { rpc } from './rpc-client';

function UserList() {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    rpc.user.listUsers().then(({ data }) => setUsers(data));
  }, []);

  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

Vue 3

<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { rpc } from './rpc-client';

const users = ref([]);

onMounted(async () => {
  const { data } = await rpc.user.listUsers();
  users.value = data;
});
</script>

Angular

import { Component, OnInit } from '@angular/core';
import { rpc } from './rpc-client';

@Component({
  selector: 'app-user-list',
  template: `
    <ul>
      <li *ngFor="let user of users">{{ user.name }}</li>
    </ul>
  `,
})
export class UserListComponent implements OnInit {
  users: any[] = [];

  async ngOnInit() {
    const { data } = await rpc.user.listUsers();
    this.users = data;
  }
}

Vanilla TypeScript

import { rpc } from './rpc-client';

async function loadUsers() {
  const { data: users } = await rpc.user.listUsers();
  console.log('Users:', users);
}

loadUsers();

🔒 Type Safety

The client automatically infers types from your server's manifest:

// Server method signature:
@Route()
async getUserById(id: string): Promise<User> {
  return { id, name: 'John', email: '[email protected]' };
}

// Client automatically gets:
const { data } = await rpc.user.getUserById('123');
//    ^? { data: User }
//    ^? id parameter is typed as string
//    ^? Full autocomplete for User properties

If your server types change, your client code will show TypeScript errors immediately!


📖 API Reference

RpcClient<Manifest>

Main client class.

const client = new RpcClient<Manifest>(config);

Config:

  • baseUrl: string - Base URL of your server
  • apiPrefix?: string - API prefix (default: 'nestjs-rpc')
  • axiosInstance?: AxiosInstance - Custom Axios instance
  • requestOptions?: AxiosRequestConfig - Default request options

client.routers()

Get the router proxy for making RPC calls.

const rpc = client.routers();
// Use rpc.user.getUserById(), etc.

client.$setConfig(config)

Update the entire configuration.

client.$setConfigProperty(key, value)

Update a single configuration property.

client.$config

Read-only access to current configuration.


🎯 Best Practices

  1. Export manifest type - Make sure your server exports export type Manifest = typeof manifest
  2. Centralize client - Create one client instance and export it
  3. Use environment variables - Use different base URLs for dev/prod
  4. Handle errors - Wrap calls in try-catch or use error boundaries
  5. Type your responses - Use const { data } destructuring for better types

💡 Examples

Check out the example directory for a complete working example with React.


📚 Need More Help?

📖 Full Documentation →

Complete guides, API reference, advanced patterns, and troubleshooting


🤝 Contributing

Contributions welcome! See the main README for details.

📄 License

MIT


Made with ❤️ for the NestJS community

⭐ Star us on GitHub📖 Documentation💬 Discussions