* WIP * Updates * Document deepEquals * WIP * Update typeS * Update TLS docs for Bun.serve * Update types for tls * Draft binary data page. Add Streams page. * Update test runner docs * Add hashing, flesh out utils * Grammar * Update types * Fix * Add import.meta docs * Tee
7.9 KiB
The page primarily documents the Bun-native Bun.serve API. Bun also implements fetch and the Node.js http and https modules.
{% callout %} These modules have been re-implemented to use Bun's fast internal HTTP infrastructure. Feel free to use these modules directly; frameworks like Express that depend on these modules should work out of the box. For granular compatibility information, see Runtime > Node.js APIs. {% /callout %}
To start a high-performance HTTP server with a clean API, the recommended approach is Bun.serve.
Bun.serve()
Start an HTTP server in Bun with Bun.serve.
Bun.serve({
fetch(req) {
return new Response(`Bun!`);
},
});
The fetch handler handles incoming requests. It receives a Request object and returns a Response or Promise<Response>.
Bun.serve({
fetch(req) {
const url = new URL(req.url);
if (url.pathname === "/") return new Response(`Home page!`);
if (url.pathname === "/blog") return new Response("Blog!");
return new Response(`404!`);
},
});
To configure which port and hostname the server will listen on:
Bun.serve({
port: 8080, // defaults to $PORT, then 3000
hostname: "mydomain.com", // defaults to "0.0.0.0"
fetch(req) {
return new Response(`404!`);
},
});
Error handling
To activate development mode, set development: true. By default, development mode is enabled unless NODE_ENV is production.
Bun.serve({
development: true,
fetch(req) {
throw new Error("woops!");
},
});
In development mode, Bun will surface errors in-browser with a built-in error page.
{% image src="/images/exception_page.png" caption="Bun's built-in 500 page" /%}
To handle server-side errors, implement an error handler. This function should return a Response to served to the client when an error occurs. This response will supercede Bun's default error page in development mode.
Bun.serve({
fetch(req) {
throw new Error("woops!");
},
error(error: Error) {
return new Response(`<pre>${error}\n${error.stack}</pre>`, {
headers: {
"Content-Type": "text/html",
},
});
},
});
{% callout %} Note — Full debugger support is planned. {% /callout %}
The call to Bun.serve returns a Server object. To stop the server, call the .stop() method.
const server = Bun.serve({
fetch() {
return new Response("Bun!");
},
});
server.stop();
TLS
Bun supports TLS out of the box, powered by OpenSSL. Enable TLS by passing in a value for key and cert; both are required to enable TLS. If needed, supply a passphrase to decrypt the keyFile.
Bun.serve({
fetch(req) {
return new Response("Hello!!!");
},
// can be string, BunFile, TypedArray, Buffer, or array thereof
key: Bun.file("./key.pem"),
cert: Bun.file("./cert.pem"),
// passphrase, only required if key is encrypted
passphrase: "super-secret",
});
The key and cert fields expect the contents of your TLS key and certificate. This can be a string, BunFile, TypedArray, or Buffer.
Bun.serve({
fetch() {},
// BunFile
key: Bun.file("./key.pem"),
// Buffer
key: fs.readFileSync("./key.pem"),
// string
key: fs.readFileSync("./key.pem", "utf8"),
// array of above
key: [Bun.file('./key1.pem'), Bun.file('./key2.pem']
});
{% callout %}
Note — Earlier versions of Bun supported passing a file path as keyFile and certFile; this has been deprecated as of v0.6.3.
{% /callout %}
Optionally, you can override the trusted CA certificates by passing a value for ca. By default, the server will trust the list of well-known CAs curated by Mozilla. When ca is specified, the Mozilla list is overwritten.
Bun.serve({
fetch(req) {
return new Response("Hello!!!");
},
key: Bun.file("./key.pem"), // path to TLS key
cert: Bun.file("./cert.pem"), // path to TLS cert
ca: Bun.file("./ca.pem"), // path to root CA certificate
});
To override Diffie-Helman parameters:
Bun.serve({
// ...
dhParamsFile: "./dhparams.pem", // path to Diffie Helman parameters
});
Hot reloading
Thus far, the examples on this page have used the explicit Bun.serve API. Bun also supports an alternate syntax.
import {type Serve} from "bun";
export default {
fetch(req) {
return new Response(`Bun!`);
},
} satisfies Serve;
Instead of passing the server options into Bun.serve, export it. This file can be executed as-is; when Bun runs a file with a default export containing a fetch handler, it passes it into Bun.serve under the hood.
This syntax has one major advantage: it is hot-reloadable out of the box. When any source file is changed, Bun will reload the server with the updated code without restarting the process. This makes hot reloads nearly instantaneous. Use the --hot flag when starting the server to enable hot reloading.
$ bun --hot server.ts
It's possible to configure hot reloading while using the explicit Bun.serve API; for details refer to Runtime > Hot reloading.
Streaming files
To stream a file, return a Response object with a BunFile object as the body.
import { serve, file } from "bun";
serve({
fetch(req) {
return new Response(Bun.file("./hello.txt"));
},
});
{% callout %}
⚡️ Speed — Bun automatically uses the sendfile(2) system call when possible, enabling zero-copy file transfers in the kernel—the fastest way to send files.
{% /callout %}
[v0.3.0+] You can send part of a file using the slice(start, end) method on the Bun.file object. This automatically sets the Content-Range and Content-Length headers on the Response object.
Bun.serve({
fetch(req) {
// parse `Range` header
const [start = 0, end = Infinity] = req.headers
.get("Range") // Range: bytes=0-100
.split("=") // ["Range: bytes", "0-100"]
.at(-1) // "0-100"
.split("-") // ["0", "100"]
.map(Number); // [0, 100]
// return a slice of the file
const bigFile = Bun.file("./big-video.mp4");
return new Response(bigFile.slice(start, end));
},
});
Benchmarks
Below are Bun and Node.js implementations of a simple HTTP server that responds Bun! to each incoming Request.
{% codetabs %}
Bun.serve({
fetch(req: Request) {
return new Response(`Bun!`);
},
port: 3000,
});
require("http")
.createServer((req, res) => res.end("Bun!"))
.listen(8080);
{% /codetabs %}
The Bun.serve server can handle roughly 2.5x more requests per second than Node.js on Linux.
{% table %}
- Runtime
- Requests per second
- Node 16
- ~64,000
- Bun
- ~160,000
{% /table %}
{% image width="499" alt="image" src="https://user-images.githubusercontent.com/709451/162389032-fc302444-9d03-46be-ba87-c12bd8ce89a0.png" /%}
Reference
{% details summary="See TypeScript definitions" %}
interface Bun {
serve(options: {
fetch: (req: Request, server: Server) => Response | Promise<Response>;
hostname?: string;
port?: number;
development?: boolean;
error?: (error: Error) => Response | Promise<Response>;
keyFile?: string;
certFile?: string;
caFile?: string;
dhParamsFile?: string;
passphrase?: string;
maxRequestBodySize?: number;
lowMemoryMode?: boolean;
}): Server;
}
interface Server {
development: boolean;
hostname: string;
port: number;
pendingRequests: number;
stop(): void;
}
{% /details %}