Skip to main content

Basic Setup

index.ts

HTML imports

Bun supports importing HTML files directly into your server code, enabling full-stack applications with both server-side and client-side code. HTML imports work in two modes: Development (bun --hot): Assets are bundled on-demand at runtime, enabling hot module replacement (HMR) for a fast, iterative development experience. When you change your frontend code, the browser automatically updates without a full page reload. Production (bun build): When building with bun build --target=bun, the import index from "./index.html" statement resolves to a pre-built manifest object containing all bundled client assets. Bun.serve consumes this manifest to serve optimized assets with zero runtime bundling overhead. This is ideal for deploying to production.
HTML imports don’t just serve HTML — it’s a full-featured frontend bundler, transpiler, and toolkit built using Bun’s bundler, JavaScript transpiler and CSS parser. You can use this to build full-featured frontends with React, TypeScript, Tailwind CSS, and more. For a complete guide on building full-stack applications with HTML imports, including detailed examples and best practices, see /docs/bundler/fullstack.

Configuration

Changing the port and hostname

To configure which port and hostname the server will listen on, set port and hostname in the options object.
To randomly select an available port, set port to 0.
You can view the chosen port by accessing the port property on the server object, or by accessing the url property.

Configuring a default port

Bun supports several options and environment variables to configure the default port. The default port is used when the port option is not set.
  • --port CLI flag
  • BUN_PORT environment variable
  • PORT environment variable
terminal
  • NODE_PORT environment variable
terminal

Unix domain sockets

To listen on a unix domain socket, pass the unix option with the path to the socket.

Abstract namespace sockets

Bun supports Linux abstract namespace sockets. To use an abstract namespace socket, prefix the unix path with a null byte.
Unlike unix domain sockets, abstract namespace sockets are not bound to the filesystem and are automatically removed when the last reference to the socket is closed.

HTTP/3 (QUIC)

HTTP/3 support in Bun.serve is experimental and may change in future releases.
Bun.serve can also listen for HTTP/3 over QUIC. Set http3: true together with tls — HTTP/3 always requires TLS.
When http3 is enabled, the server listens on the same port over both TCP (HTTP/1.1) and UDP (HTTP/3). HTTP/1.1 responses include an Alt-Svc header advertising the HTTP/3 endpoint so capable clients can upgrade automatically. To serve HTTP/3 only — no TCP listener at all — set http1: false:
http3 is not supported with unix domain sockets — QUIC requires a UDP port. http1: false requires http3: true.

idleTimeout

By default, Bun.serve closes connections after 10 seconds of inactivity. A connection is considered idle when there is no data being sent or received — this includes in-flight requests where your handler is still running but hasn’t written any bytes to the response yet. Browsers and fetch() clients will see this as a connection reset. To configure this, set the idleTimeout field (in seconds). The maximum value is 255, and 0 disables the timeout entirely.
Streaming & Server-Sent Events — The idle timer applies while a response is being streamed. If your stream goes quiet for longer than idleTimeout, the connection will be closed mid-response. For long-lived streams, disable the timeout for that request with server.timeout(req, 0).

export default syntax

Thus far, the examples on this page have used the explicit Bun.serve API. Bun also supports an alternate syntax.
server.ts
The type parameter <undefined> represents WebSocket data — if you add a websocket handler with custom data attached via server.upgrade(req, { data: ... }), replace undefined with your data type. Instead of passing the server options into Bun.serve, export default it. This file can be executed as-is; when Bun sees a file with a default export containing a fetch handler, it passes it into Bun.serve under the hood.

Hot Route Reloading

Update routes without server restarts using server.reload():

Server Lifecycle Methods

server.stop()

To stop the server from accepting new connections:
By default, stop() allows in-flight requests and WebSocket connections to complete. Pass true to immediately terminate all connections.

server.ref() and server.unref()

Control whether the server keeps the Bun process alive:

server.reload()

Update the server’s handlers without restarting:
This is useful for development and hot reloading. Only fetch, error, and routes can be updated.

Per-Request Controls

server.timeout(Request, seconds)

Override the idle timeout for an individual request. Pass 0 to disable the timeout entirely for that request.
This is the recommended way to keep long-lived streaming responses (like Server-Sent Events) alive without raising the global idleTimeout for every request:

server.requestIP(Request)

Get client IP and port information:
Returns null for closed requests or Unix domain sockets.

Server Metrics

server.pendingRequests and server.pendingWebSockets

Monitor server activity with built-in counters:

server.subscriberCount(topic)

Get count of subscribers for a WebSocket topic:

Benchmarks

Below are Bun and Node.js implementations of an HTTP server that responds Bun! to each incoming Request.
Bun
The Bun.serve server can handle roughly 2.5x more requests per second than Node.js on Linux.
image

Practical example: REST API

Here’s a basic database-backed REST API using Bun’s router with zero dependencies:

Reference

See TypeScript Definitions