OpenMesh GitHub ↗
TypeScript service runtime for Node.js

Build services.
Skip the glue.

Start with a normal Node.js API. Grow into an application-native service mesh with discovery, traffic policy, bounded failure handling, workload identity and observability inside the same TypeScript runtime.

$ npm install openmesh-node
v0.5.0 Node.js ≥ 22 Strict TypeScript ESM + CommonJS Zero core runtime dependencies
runtime OpenMesh API → mesh
gatewayrouting
users-ahealthy
users-bhealthy
controlwatching
02 · Code

Start small.
Add the mesh when you need it.

HTTP routing is useful by itself. Database lifecycle, discovery, traffic policy, workload identity and peer calls are separate layers rather than mandatory ceremony.

server.ts
import openmesh from 'openmesh-node';
import { bodyParser } from 'openmesh-node/plugins';

const app = openmesh();
app.use(bodyParser());

app.get('/users/:id', ({ params }) => ({
  id: params.id
}));

await app.listen({ port: 3000 });
03 · Mesh benchmark

Measure the whole service call.

The 0.5 benchmark now measures application-to-application invocation, not framework-only HTTP routing. Every path uses the same Node caller and target; only the mesh data plane changes.

Application-native Sidecar data plane Methodology + raw results ↗
Directcaller → target
Envoy 1.37.2caller → outbound → inbound → target
Dapr 1.18.4caller → daprd → daprd → target
BaselineDirect
2,987req/s
p99
30 ms
CPU sum
106.5%
RSS sum
133.5 MiB
C++ · 2 proxiesEnvoy
1,281req/s
p99
58 ms
CPU sum
183.8%
RSS sum
192.9 MiB
Go · 2 sidecarsDapr
1,243req/s
p99
63 ms
CPU sum
197.5%
RSS sum
336.5 MiB
+41% throughput vs two-proxy Envoy
+45% throughput vs two-sidecar Dapr

Median of five 5-second rounds, 32 connections, pipelining 1, Node 24.21.0 on an Intel i5-8279U Mac. Envoy uses one worker; Dapr uses GOMAXPROCS=1. Plain HTTP baseline — TLS/mTLS is intentionally measured separately, not mixed into this result.

04 · Why OpenMesh

The difference is not another router.

OpenMesh keeps the HTTP core small, then adds the service-runtime concerns that usually become separate libraries, sidecars and application glue.

01

Start as an API. Grow into a mesh.

Keep normal app.get/post routes, your existing ORM and application lifecycle. Add lazy app.mesh('service') handles only when services split.

02

Discovery and traffic policy are live runtime state.

Registration leases, resumable membership watches, weighted subsets, header routes, locality preference and live policy replacement feed the same warm service pool.

03

Failure and overload stay bounded.

Deadlines, safe retries, circuits, queues, bulkheads, adaptive concurrency and true streaming semantics are part of peer calls rather than scattered caller code.

04

Identity and telemetry stay inside the application boundary.

SPIFFE-style workload identity, mutual TLS, certificate rotation, trace propagation and an OpenTelemetry-compatible metrics bridge remain opt-in runtime layers.

05 · Technical guides

Explore the runtime by problem.

Focused explanations for the Node.js microservices problems OpenMesh is designed to solve, with architecture, failure semantics and runnable TypeScript examples.