@nextrush/adapter-bunBun
Bun HTTP adapter for NextRush with graceful shutdown and TLS support.
Connect your NextRush application to Bun's native HTTP server.
This adapter bridges NextRush's middleware system to Bun's native Bun.serve() API, handling context creation, in-flight request tracking, and graceful shutdown.
Source & internals
README · ARCHITECTURE · see also Adapter Contract
| Package | @nextrush/adapter-bun |
| Status | Stable |
| Support tier | Public — stable (sealed public API) |
Included in nextrush? | No — standalone install |
| Runtime | Bun >=1.0.0 only |
Installation
$ pnpm add @nextrush/adapter-bun @nextrush/core
Bun Runtime Required
This adapter requires Bun 1.0 or later. It uses Bun's native
Bun.serve() API for optimal performance.
Quick Start
import { createApp } from '@nextrush/core';
import { listen } from '@nextrush/adapter-bun';
const app = createApp();
app.use(async (ctx) => {
ctx.json({ runtime: 'bun', message: 'Hello World!' });
});
listen(app, 8080);
// Output: 🚀 NextRush listening on http://localhost:8080 (Bun)Run with Bun:
bun run src/index.tsAPI Reference
serve(app, options?)
Start the HTTP server with full configuration control.
import { createApp } from '@nextrush/core';
import { serve } from '@nextrush/adapter-bun';
const app = createApp();
const server = serve(app, {
port: 8080,
host: '0.0.0.0',
development: true,
onListen: ({ port, hostname }) => {
console.log(`Server running at http://${hostname}:${port}`);
},
onError: (error) => {
console.error('Server error:', error);
},
});ServeOptions
Options
| Property | Type | Description |
|---|---|---|
port | number= 8080 | Port to listen on |
host | string= '0.0.0.0' | Host to bind to |
onListen? | (info: { port: number; host: string; hostname: string }) => void | Callback when server starts listening |
onError? | (error: Error) => void | Custom handler for uncaught server errors |
tls? | { cert: string | Buffer; key: string | Buffer; ca?: string | Buffer } | TLS/HTTPS configuration |
maxRequestBodySize? | number | Maximum request body size in bytes (Bun default: 128 MB) |
development | boolean= false | Enable Bun development mode with additional logging |
shutdownTimeout | number= 30000 | Grace period in ms to drain in-flight requests during shutdown |
gracefulShutdown? | boolean | GracefulShutdownOptions | Opt-in: wire SIGTERM/SIGINT to the same close() drain logic. `true` installs handlers for the default signal set; `{ signals, timeout }` overrides them. Omitted by default — no signal handler is installed and process behavior is unchanged. |
ServerInstance
The returned server instance provides control methods:
interface ServerInstance {
server: ReturnType<typeof Bun.serve>; // Underlying Bun server
port: number; // Actual port
hostname: string; // Actual hostname
close(): Promise<void>; // Graceful shutdown (drains in-flight requests)
address(): { port: number; hostname: string };
reload(options?: Partial<ServeOptions>): void; // Reload server configuration
}close() stops accepting new connections, waits up to shutdownTimeout ms for in-flight requests
to complete, then force-closes remaining connections and notifies plugins via app.close().
listen(app, port?)
Quick-start shorthand with default logging.
import { createApp } from '@nextrush/core';
import { listen } from '@nextrush/adapter-bun';
const app = createApp();
const server = listen(app, 8080);
// Output: 🚀 NextRush listening on http://localhost:8080 (Bun)createHandler(app)
Create a raw fetch handler for advanced use cases.
import { createApp } from '@nextrush/core';
import { createHandler } from '@nextrush/adapter-bun';
const app = createApp();
const handler = createHandler(app);
// Use directly with Bun.serve
Bun.serve({
fetch: handler,
port: 8080,
});TLS/HTTPS
Enable HTTPS with TLS certificates:
import { serve } from '@nextrush/adapter-bun';
const server = serve(app, {
port: 443,
tls: {
cert: Bun.file('./cert.pem'),
key: Bun.file('./key.pem'),
ca: Bun.file('./ca.pem'), // Optional CA certificate
},
});No HTTP/2 negotiation on this option
Verified directly against Bun.serve(): its native tls option serves HTTPS/1.1 only — it does
not negotiate h2 via ALPN. getRuntimeCapabilities().http2 reports false on Bun. See the
HTTPS & HTTP/2 guide for the cross-runtime picture, including where
Deno and Node differ.
Hot Reload
Bun adapter supports runtime configuration reload:
const server = serve(app, { port: 8080 });
// Update non-structural configuration at runtime
server.reload({ development: true });reload() passes options to Bun's server.reload(). Structural changes like port may not take effect.
Request Body Limits
Configure maximum request body size:
const server = serve(app, {
port: 8080,
// 10MB limit
maxRequestBodySize: 10 * 1024 * 1024,
});maxRequestBodySize defaults to 1 MB, not Bun's own 128 MB Bun.serve() default — NextRush
overrides it deliberately at the server level so this adapter's default matches
@nextrush/body-parser's JSON default. Raise it explicitly for routes that need larger uploads.
Development Mode
Enable development mode for additional logging:
const server = serve(app, {
port: 8080,
development: true, // Enables Bun's dev logging
});Graceful Shutdown
The adapter tracks in-flight requests and drains them on shutdown. Configure the drain timeout with shutdownTimeout (default: 30 seconds):
const server = serve(app, {
port: 8080,
shutdownTimeout: 10_000, // 10s drain window
});
process.on('SIGTERM', async () => {
await server.close();
process.exit(0);
});close() performs three steps:
- Stops accepting new connections
- Waits for active requests to finish (up to
shutdownTimeout) - Force-closes remaining connections and calls
app.close()
Wiring the signal handlers yourself (as above) works, but gracefulShutdown does it for you:
const server = await serve(app, {
port: 8080,
gracefulShutdown: true, // installs SIGTERM + SIGINT, using shutdownTimeout as the drain window
});
// Or override the signal set / drain timeout explicitly:
const server2 = await serve(app, {
port: 8080,
gracefulShutdown: { signals: ['SIGTERM'], timeout: 5_000 },
});Omitting gracefulShutdown installs no signal handler — process behavior is unchanged. The
handler is removed once close() completes, so repeated serve()/close() cycles never
accumulate duplicate listeners.
Client IP Access
The adapter automatically extracts client IP from Bun's requestIP():
app.use(async (ctx) => {
// Available via context
const ip = ctx.ip; // Extracted from Bun server
ctx.json({ clientIp: ip });
});TypeScript
Full TypeScript support with proper types:
import type { Application } from '@nextrush/core';
import type { ServeOptions, ServerInstance } from '@nextrush/adapter-bun';
import { serve, listen, createHandler } from '@nextrush/adapter-bun';
const options: ServeOptions = {
port: 8080,
development: process.env.NODE_ENV !== 'production',
};
const server: ServerInstance = serve(app, options);Related
- Platforms Overview — Understanding runtime adapters
- @nextrush/adapter-node — Node.js adapter
- @nextrush/adapter-edge — Edge runtime adapter
- @nextrush/runtime — Runtime detection utilities