Transparent TypeScript RPC; Compact Wire Format that Rivals gRPC

Convert standard TypeScript functions into RPC calls with a compact binary representation that is mostly faster and smaller than gRPC and Protobufs.

Client
Orithmic
Year
2026
Read
6 min
Role
Founder & Lead Systems Engineer
  • RPC
  • Transformers
  • Code generation
  • Binary codec
  • SWC
  • OXC
  • Rust
  • TypeScript

Code has always been a source of truth. It is not only where people and increasingly, agents implement systems, but also where interfaces are defined and documented. With most applications built for the web, it makes sense that software is increasingly developed using JavaScript on both the frontend and backend. Sharing common libraries and functions across the client server boundary is immensely beneficial, and a vast package ecosystem only makes the case more appealing.

While AI agents increasingly write most of the application layer code, a strong case can be made for lower level languages. Large library archives and a shared language become less important when you can simply prompt a system to generate more code. However, maintenance overhead tends to grow exponentially with every additional line. The question remains: will people be responsible for reviewing code in the future? It remains to be seen, but we might be looking at a major rewrite of the layers we use to build, manage, and distribute software. I’ve been experimenting with this concept and will share more in the future.

Back to JavaScript, the common language between servers and browsers. While both can run the same code, there are obvious reasons why we don’t want some code running in the browser. Hence, the server exists. But this introduces a problem: we now need to build and document endpoints on the server and create serialization systems to encode and decode messages across the client server barrier. While many existing solutions address this issue, they all add operational overhead that isn’t natural to the development pipeline, along with a lot of boilerplate.

At Orithmic, an alternative approach was taken. Similar to documentation, TypeScript was leveraged as the common source of truth. This moves the complexity out of the application and library layer. Defining boundaries is transparent. It’s as simple as building standard, asynchronous TypeScript functions with defined types. The only difference is that they are exported from marked files. Then, you simply import and call them from the client side like any other exported function. In the background, Orithmic RPC parses the marked TypeScript files and derives efficient binary serializers that can encode and decode the request and response sequence, as well as the transport needed to call the function.

Example

Server Example:

// file: /api/users.fn.ts

// Define a standard user type
export interface User {
  id: string;
  name: string;
}

// Define a standard event type
export interface Event {
  type: string;
  timestamp: number;
}

// Define a standard function
export async function getUser(id: string): Promise<User> {
  return { id, name: "Alice" };
}

// Generators also work!
export async function* streamEvents(userId: string): AsyncGenerator<Event, void> {
  while (true) {
    const event = await nextEvent(userId);
    yield event;
  }
}

Client Example:

import { User, Event, getUser } from "/api/users.fn.ts";

const user = await getUser("123");
console.log(user);

for await (const event of streamEvents(user.id)) {
  console.log(event);
}

Supported Types

  • Primitives: string, number, boolean, null, undefined, bigint
  • Literals (not encoded): string, number, and boolean literals
  • Collections: arrays (T[], Array<T>), tuples ([A, B]), Set<T>, Map<K, V>, Records ({ [key: string]: V })
  • Objects and interfaces: inline object types and interface/type alias declarations
  • Unions: A | B with discriminants
  • Optional values: T | undefined and T?
  • Enums: TypeScript enum
  • Promises: Promise<T> for async function results
  • Async iterables: AsyncIterable<T> and AsyncGenerator<T> for streaming
  • Special types: Uint8Array and other typed arrays, Date
  • Escape type: Local<T> for data that is not sent on the wire
  • Custom classes: More on this later, as this wasn’t as straightforward
  • RPCError: A custom error for non recoverable network errors

Why not JSON? It is easier to debug/read

While true, it is definitely a tool issue. While debugging and tracing is critical it should not add overhead to the wire representation. In the age where tool building is accelerated, this will become less of a problem, making a stronger case for efficient representations that don’t sacrifice observability.

Why not gRPC or Protobufs

No schema files to maintain, no scaffolding, no boilerplate, and the binary format is compressed and way more efficient than JSON and even gRPC. While the initial approach was to parse and generate gRPC compatible endpoints, the new wire protocol proved to be more flexible and efficient at representing TypeScript types.

While that might seem simple enough, the challenge is in how type mutations are handled with minimal impact on the wire format. Unlike Protobufs which move the overhead of mutations to the wire format.

But this is only the beginning of the challenges… In the future, I plan to share more about how the underlying system works, along with a few benchmarks…

Will AI Agents Write Everything?

In the age of AI, does it matter how big your code base is, how complicated the scaffolding layers are, or the amount of scattering and duplication that occurs from other protocols? As of today, context matters. People still review many codebases, especially as functionality gets increasingly complex, which all worthwhile software eventually does.

Competition is not about replication; it is about innovating above the baseline. Innovating is challenging and requires way more effort than replicating. 90% of the work is in the discovery; doing anything the second time is always faster and easier. AI just makes the easier part even easier. For the future, clean and efficient codebases will always be easier to manage and scale. Whether people or agents are doing the grunt work, context will likely matter.

Summary & Closing Thoughts

The goal of Orithmic RPC is to make the web faster by making applications simpler to build and less wasteful, without the overhead of defining or interfacing that accompanies other protocols. The goal is to make less code more powerful in its representation and more efficient to run.

Keep an eye out for future blog posts, where I will go into more depth on the protocol and how it is used to power every part of the Orithmic Platform (including a more compact JWT token), which is launching soon.

Orithmic’s goal is to make building applications more accessible and sustainable. If you have an idea for a tool that will make you more efficient or competitive at your job, or an application that you always wanted to build and maybe even monetize… While other platforms might bring down the entry barrier, it comes at the cost of future advancements when you need to build features that require true innovation or scale. Most of the value is in innovating, which is the most challenging part. Orithmic seeks to remove barriers so more people can innovate without introducing obstacles down the line.

Follow me on LinkedIn or star and watch the repository Github for updates.

Let's work together

Got something worth building? Let's talk.

Choices are saved in this browser only.