// define on server:
export const sayHello = (x, y) => `${x}, meet ${y}.`
sayHello.rpc = true
// call on client:
const hello = await sayHello("Backend", "Frontend")

meet Frontend.

RPC for the Rest of Us.

Prim+RPC bridges incompatible environments in JavaScript. Call functions defined on the server as if they exist on the client, without the setup, event mapping, or wrappers.

It's Just JavaScript

If you know JavaScript basics, you know how to use Prim+RPC.

No Type Guessing

Get full type definitions in your client using TypeScript or JSDoc.

Zero Client Generation

Calls are generated at runtime, skip the build step, if you want.

Bring Your Own Server

It's framework agnostic and includes lots of popular integrations.

Choose Your Client

Don't like the default method of sending requests? Swap it out.


Bridge client/server, web workers, proceses and more. It's not just HTTP.

Write a Function. Call It. Done.

Prim+RPC is designed to work with your existing tools. It's sole focus is to create and respond to RPC, not to dicate what tools that you use to send it.


Write your function

No magic involved: they're just plain JavaScript functions.

export function sayHello() {
	return "Hello world!"
// This property signals to Prim+RPC that this function can be exposed
sayHello.rpc = true

Create the server

Prim+RPC supports your existing server framework.

import { createPrimServer } from "@doseofted/prim-rpc"
import { primFetch } from "@doseofted/prim-rpc-plugins/server-fetch"
import * as module from "./module"

// Server routes are automatically created for your functions
export default primFetch({
	prim: createPrimServer({ module }),
export type Module = typeof module

Create the client

Prim+RPC handles the client/server dance.

import { createPrimClient } from "@doseofted/prim-rpc"
import { createMethodPlugin } from "@doseofted/prim-rpc-plugins/browser-fetch"
import type { Module } from "../server"

// The Prim client knows how to call functions on the server
export default createPrimClient<Module>({
	endpoint: "http://localhost:3000/prim",
	methodPlugin: createMethodPlugin(),

Call your function

No wrappers or client generation. Just call the function.

import client from "./prim"

// Function calls are automatically translated into RPC in the background
const message = await client.sayHello()
console.log(message) // Hello world!

It Works Everywhere. With Everything.

Prim+RPC works in all JavaScript envrionments: Node, Deno, Bun, browser, wherever. It supports many frameworks already and can be extended to work with any framework.

Oh, but that's not all.

Prim+RPC does the heavy lifting so you can use JavaScript features between server and client that would otherwise be difficult.

Handle Files

Files and Blobs are fully supported without all of the extra work.

Use Callbacks

Use callbacks between server and client: great for real-time events.

Advanced Types Supported

Use a custom JSON handler to support Dates, RegExps, Errors, and more.

Throw Errors

No error code mapping needed. Errors on the server are errors on the client.

Forms Supported

You don't need to process HTML forms. Supports all fields, including files.

Build a Public API

Build an API either for internal usage or to share with the world.

Batch RPCs

Multiple function calls are batched into single requests easily.

Share Only What's Allowed

Only the functions you explicitly export and mark as RPC are callable.

Generate Documentation

Build documentation of your functions directly from your existing TypeDoc.

Modular & Test Friendly

Function logic is separate from the transport, makes testing easy.

It's Available Now. Right Now.

Easy to setup, lots of features, and open source. Try it out!