Skip to content

NwireOne handler, every transport.

Write your backend logic once. Run it under HTTP, a queue, cron, or MCP — with auth, storage, email, a live trace view, and production defaults built in. The deep stuff is there when you need it, never in your way when you don't.

Hello world

ts
import { createApp } from "@nwire/app";
import { endpoint } from "@nwire/endpoint";
import { get } from "@nwire/wires/http";
import { httpKoa } from "@nwire/koa";

const app = createApp({ appName: "hello" });
app.wire(get("/hello"), async () => ({ message: "hello world" }));

await endpoint("hello", { port: 3000 }).use(httpKoa()).mount(app).run();

One typed route, graceful shutdown, and K8s probes — no extra setup. Just a handler on a transport.

The same handler, another transport

This is the seam Nwire is built around. Write the operation once, then expose it through as many transports as make sense. The logic does not change:

ts
import { createApp } from "@nwire/app";
import { endpoint } from "@nwire/endpoint";
import { post } from "@nwire/wires/http";
import { queue } from "@nwire/wires/queue";
import { httpKoa } from "@nwire/koa";
import { queueInMemory } from "@nwire/queue";
import { z } from "zod";

const app = createApp({ appName: "billing" });

// one handler — a plain typed function
const charge = async (input: { orderId: string }) => ({ charged: input.orderId });

app.wire(post("/orders/:orderId/charge", { params: z.object({ orderId: z.string() }) }), charge);
app.wire(queue("orders.charge", { input: z.object({ orderId: z.string() }) }), charge);

await endpoint("billing", { port: 3000 })
  .use(httpKoa())        // serves the HTTP route
  .use(queueInMemory())  // serves the same handler as a queue worker
  .mount(app)
  .run();

POST /orders/o-1/charge and an enqueue to orders.charge run the identical handler. Swap queueInMemory() for @nwire/bullmq to back it with Redis — the handler still doesn't change.

Walk through it step by step · Why it's shaped this way · Get started

Status

Pre-release, MIT-licensed, driving production at 200apps. Some APIs may still change before 1.0. Source and issues on Bitbucket.

MIT licensed.