- What: A tiny, Bun-native adapter for running tRPC over Bun.serve with first-class HTTP and WebSocket support.
- Why: Use Bun’s latest APIs with tRPC v11 — no Node.js shims.
- How: HTTP via
fetchadapter + Bun’supgrade; WS via Bun’swebsockethandler; one-liner server composer; optional reconnect broadcast.
- Features
- Requirements
- Install
- Quickstart
- Usage
- API
- Repository overview
- Contributing
- License
- Acknowledgments
- Contact
- Bun 1.3+ native HTTP (
Bun.serve) + WS (websockethandler) - tRPC 11.6+ using only public server APIs
- Simple adapters:
createTrpcBunFetchAdapter(HTTP)createTrpcBunWebSocketAdapter(WS)configureTrpcBunServer(compose HTTP + WS forBun.serve)broadcastReconnectNotification(server-initiated WS notification)
- Connection params over WS, subscriptions, mutations, error shaping
- Duplicate id protection, graceful stop/disconnect handling
- Test suite with
bun testand GitHub Actions CI
- Bun ≥ 1.3.0
- @trpc/server ≥ 11.6.0
- TypeScript ≥ 5
# with bun
bun add trpc-bun @trpc/server
# or npm
npm install trpc-bun @trpc/serverPeer dependencies: Bun runtime, TypeScript.
import { initTRPC } from "@trpc/server";
import { configureTrpcBunServer } from "trpc-bun";
const t = initTRPC.create();
const appRouter = t.router({
hello: t.procedure.query(() => "world"),
});
Bun.serve(
configureTrpcBunServer({
router: appRouter,
endpoint: "/trpc",
}),
);- Uses
globalThis.Bun.Serve.Options<T>(not deprecatedServeOptions).
import { initTRPC } from "@trpc/server";
import { createTrpcBunFetchAdapter } from "trpc-bun";
const t = initTRPC.create();
const router = t.router({ hello: t.procedure.query(() => "world") });
const trpcFetch = createTrpcBunFetchAdapter({ router, endpoint: "/trpc" });
Bun.serve({
fetch(req, server) {
return trpcFetch(req, server) ?? new Response("fallback");
},
});import { initTRPC } from "@trpc/server";
import { createTrpcBunWebSocketAdapter } from "trpc-bun";
const t = initTRPC.create();
const router = t.router({
numbers: t.procedure.subscription(() =>
async function* () { yield 1; yield 2; }
),
});
Bun.serve({
fetch() { return new Response("OK"); },
websocket: createTrpcBunWebSocketAdapter({ router }),
});import { configureTrpcBunServer } from "trpc-bun";
Bun.serve(
configureTrpcBunServer({ router, endpoint: "/trpc" })
);import { broadcastReconnectNotification } from "trpc-bun";
// Later in your deploy hook or admin path:
const sent = broadcastReconnectNotification();
console.log(`sent ${sent} reconnect notifications`);createTrpcBunFetchAdapter<TRouter, WSData>(opts)endpoint?: stringroute prefix (e.g. "/trpc")createContext?(opts)standard tRPC fetch context- Uses Bun’s
server.upgradewhenemitWsUpgradesis enabled by the composer
createTrpcBunWebSocketAdapter<TRouter>(opts)createContext?(opts)providesreq,res(ServerWebSocket), andinfo- Supports
connectionParamshandshake and subscriptions
configureTrpcBunServer<TRouter>(opts, serveOptions?)- Returns
globalThis.Bun.Serve.Options<WebSocketData>withfetchandwebsocket - Forwards non-matching routes to your own
serveOptions.fetch
- Returns
broadcastReconnectNotification()- Broadcasts
{ id: null, method: "reconnect" }to all open sockets managed by the adapter
- Broadcasts
For advanced usage, explore src/ and tests.
.
├─ src/
│ ├─ fetchAdapter.ts # HTTP adapter (Bun fetch + upgrade)
│ ├─ websocketAdapter.ts # WebSocket adapter (Bun websocket handler)
│ ├─ serverAdapter.ts # Composer for Bun.serve
│ ├─ websocketBroadcaster.ts # Reconnect broadcast helper
│ └─ e2e.test.ts # bun:test suite
├─ .github/workflows/ci.yml # CI with bun lint/test/typecheck
└─ README.md
- Issues and PRs welcome! Please:
- Run
bun run lint && bun run typecheck && bun testbefore submitting - Keep changes small and well-documented
- Add/extend tests when changing behavior
- Run
Local dev scripts:
bun run lint
bun run format
bun run typecheck
bun testMIT — see LICENSE.txt
- tRPC team for excellent server primitives
- Author: Luis —
luismmorales@gmail.com - GitHub:
lacion