Skip to content

Repository files navigation

@layra/rpc — Declarative DTOs with Zero-Allocation Binary Protocol

Write NestJS-like decorators. Get C-level serialisation performance.

@Dto()
class CreateUserDto {
  @Field('string', 32) firstName!: string;
  @Field('string', 32) lastName!: string;
  @Field('number')     age!: number;
  @Field('string', 32) email!: string;
  @Field('string', 1)  sex!: string;
  @Field('string', 32) password!: string;
  @Field('boolean')    active!: boolean;
}

Why?

JSON serialisation allocates memory on every request — JSON.parse creates objects, JSON.stringify creates strings. Under high load, GC pauses eat your latency budget.

@layra/rpc inverts the model:

  1. You declare your DTO with decorators (no manual offset calculations)
  2. Code generator produces monomorphic read/write functions with compile-time constants
  3. DtoPool pre-creates all DTO+Buffer pairs at startup — zero allocations on hot path
  4. Getters read directly from the binary buffer — no object creation per request

Installation

npm install @layra/rpc

Or directly from GitHub:

{
  "dependencies": {
    "@layra/rpc": "dualitysol/layra-rpc"
  }
}

Quick Start

1. Define your DTOs

// user.dto.ts
import { Dto, Field } from '@layra/rpc';

@Dto()
class CreateUserDto {
  @Field('string', 32) firstName!: string;
  @Field('string', 32) lastName!: string;
  @Field('number')     age!: number;
  @Field('string', 32) email!: string;
  @Field('string', 32) password!: string;
  @Field('boolean')    active!: boolean;
}

@Dto()
class UserCreatedDto {
  @Field('boolean')         success!: boolean;
  @Field('string', 128)     message!: string;
}

2. Generate binary view

npx layra-compile src/user.dto.ts src/generated/user.dto.ts

This produces:

// Generated: SIZE, OFFSET_XXX, readXxx(), writeXxx(), createDTO(), writeToBuffer()
export const SIZE = 167;              // total buffer size
export const OFF_FIRSTNAME = 0;       // byte offsets — auto-calculated
export const OFF_LASTNAME  = 33;
// ...

// Monomorphic — V8 inlines these
export function readFirstName(buf: Buffer): string { ... }
export function writeEmail(buf: Buffer, value: string): void { ... }

// Shared prototype — zero alloc per instance
export function createDTO(buf: Buffer): CreateUserDtoView { ... }

3. Use DtoPool for zero-alloc request handling

import { DtoPool } from '@layra/rpc';
import { createDTO, SIZE } from './generated/user.dto';

const pool = new DtoPool(createDTO, SIZE, 50000);

// Hot path — every request:
const { dto, buf } = pool.acquire();
// stream request body into `buf`
const email = dto.email;  // ← getter reads from buf, zero alloc!
pool.release({ dto, buf });

4. Or use the full RPC server

import { Dto, Field, Method, UseCase } from '@layra/rpc';

@Method({ name: 'CreateUser', payload: CreateUserDto, response: UserCreatedDto })
class CreateUserUseCase extends UseCase {
  handle(dto: CreateUserDto): UserCreatedDto {
    return { success: true, message: dto.email };
  }
}

Performance

Tested on Node.js 24 with autocannon (100 connections, 15s):

Metric @layra/rpc (binary) Fastify (JSON) Improvement
RPS (avg) 56,613 38,534 +47%
Latency (avg) 1.16 ms 2.22 ms -48%
Latency (p99) 4.00 ms 8.00 ms -50%
Throughput 15.87 MB/s 8.27 MB/s +92%

API

Decorators

Decorator Description
@Dto() Marks a class as a DTO
@Field(type, maxLen?) Declares a field with type
@Method(opts) Registers a use case handler

Runtime

Export Description
DtoPool Zero-allocation pool of pre-created DTOs
BufferPool Generic buffer pool
FixedBufferPool Same-size buffer pool
createServer() Create a TCP RPC server

Codegen

Export / CLI Description
generateBinaryView(cls) Generate TS code from a DTO class
layra-compile <input> CLI wrapper around the generator

Subpath imports

import { ... } from '@layra/rpc';              // Main — decorators, runtime, pool
import { generateBinaryView } from '@layra/rpc/codegen';  // Code generator
import { DtoPool } from '@layra/rpc/runtime';   // Runtime only
import { createServer } from '@layra/rpc/server';  // TCP server

License

ISC © Artem Tantsura

About

My own custom RPC experimental protocol for high-load and low latency projects built with using binary formatting and my own ObjectPool implementation

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages