---
id: "titan/netron"
title: "Netron RPC"
description: "A transport-agnostic RPC plane — same service surface across HTTP, WebSocket, TCP, Unix."
---

# Netron RPC

Netron is the RPC plane Titan ships. It does one thing: take a
TypeScript class, expose its methods over the wire, dispatch incoming
calls back to the methods. The wire format is binary msgpack; the
contract is the TypeScript interface.

This page is the Netron entry point. The mechanics live in:

| Page                                                | Topic                                               |
| --------------------------------------------------- | --------------------------------------------------- |
| [Services](/docs/titan/netron/services)             | Defining `@Service` classes, descriptors, peers     |
| [Transports](/docs/titan/netron/transports)         | HTTP / WebSocket / TCP / Unix — when to choose what |
| [Middleware](/docs/titan/netron/middleware)         | Per-call wrapping (auth, rate limit, tracing)       |
| [Authentication](/docs/titan/netron/authentication) | Identity, claims, policies                          |
| [Streaming](/docs/titan/netron/streaming)           | AsyncIterable methods, backpressure                 |
| [Multi-backend](/docs/titan/netron/multi-backend)   | Client → many servers, failover, load balancing     |
| [Serialization](/docs/titan/netron/serialization)   | Wire format, msgpack, custom codecs                 |

## The short tour

Server — define the service, then bind a transport server on the
running `Netron` instance:

```typescript
import { Service, Public } from '@omnitron-dev/titan/decorators';
import { HttpTransport } from '@omnitron-dev/titan/netron/transport/http';

@Service('users@1.0.0')
class UsersService {
  @Public() async findById(id: string): Promise<User | null> { /* … */ }
}

const app = await Application.create(AppModule);
app.netron!.registerTransport('http', () => new HttpTransport());
app.netron!.registerTransportServer('http', { name: 'api', options: { host: '127.0.0.1', port: 3000 } });
await app.start();
```

Client — connect to get a `RemotePeer`, then resolve a typed proxy:

```typescript
const peer  = await app.netron!.connect('http://127.0.0.1:3000');
const users = await peer.queryInterface<UsersService>('users@1.0.0');
const user  = await users.findById('u_42');
```

That is the core API surface. Versioning, routing, serialisation,
error mapping, and trace propagation all happen behind it.

> The in-browser client is a separate package
> (`@omnitron-dev/netron-browser`) with its own connection API; this
> page covers the server-side `@omnitron-dev/titan/netron` runtime.

## What Netron is

A few specific things, each with a deliberate scope:

- **A service descriptor system.** `@Service` registers a typed
  contract; clients resolve it by name and version.
- **A transport abstraction.** Four transports built in, all sharing
  the same service surface; pluggable for custom ones.
- **A middleware pipeline (HTTP transport).** Per-call wrapping for
  cross-cutting concerns — auth, rate limiting, tracing, logging. The
  persistent transports (WS/TCP/Unix) enforce auth inline at dispatch
  rather than through the pipeline.
- **An auth policy framework.** Authentication and authorisation are
  separate concerns with composable policies via `BuiltInPolicies`
  (`requireRole`, `requireAnyRole`, `requirePermission`, …).
- **A multi-backend client.** One client can route to many servers
  with health-aware failover, circuit breaking, and per-service
  routing rules.
- **A streaming primitive.** `NetronReadableStream` /
  `NetronWritableStream` (Node Web Streams) carry long-lived data over
  WebSocket / TCP / Unix. An `async *` generator method is
  auto-wrapped into a stream for remote callers.

## What Netron is not

- **Not a service mesh.** Discovery, mTLS, traffic shaping at
  cluster scope are out of scope. Use a real mesh (Linkerd, Istio,
  Consul Connect) for that.
- **Not a queue.** Netron calls are request/response; the response
  may be a stream. For decoupled work, use
  [`titan-events`](/docs/titan/modules/events) or
  [`titan-notifications`](/docs/titan/modules/notifications).
- **Not a schema language.** The TypeScript interface is the schema.
  No `.proto` files, no OpenAPI YAML.

## Performance characteristics

Per-call cost on a warmed-up connection (HTTP/1.1, localhost,
no middleware):

| Op                             | Approx cost |
| ------------------------------ | ----------- |
| msgpack encode (small payload) | 5–10 µs     |
| Service descriptor lookup      | <1 µs       |
| Validation (typical schema)    | 1–5 µs      |
| Method invocation (your code)  | varies      |
| msgpack decode                 | 5–10 µs     |
| HTTP framing                   | 50–200 µs   |

For sustained throughput, use WebSocket (no per-call HTTP framing
cost) or TCP. For bursty short-lived clients, HTTP is fine and works
through any reverse proxy.