home / skills / secondsky / claude-skills / bun-http-server
This skill helps you build high-performance Bun HTTP servers, handle requests, routing, and responses with practical code patterns.
npx playbooks add skill secondsky/claude-skills --skill bun-http-serverReview the files below or copy the command above to add this skill to your agents.
---
name: Bun HTTP Server
description: Use when building HTTP servers with Bun.serve, handling requests/responses, implementing routing, creating REST APIs, or configuring fetch handlers.
version: 1.0.0
---
# Bun HTTP Server
Bun has a built-in high-performance HTTP server via `Bun.serve()`.
## Quick Start
```typescript
const server = Bun.serve({
port: 3000,
fetch(req) {
return new Response("Hello World!");
},
});
console.log(`Server running at http://localhost:${server.port}`);
```
## Request Handling
```typescript
Bun.serve({
fetch(req) {
const url = new URL(req.url);
// Method
console.log(req.method); // GET, POST, etc.
// Path
console.log(url.pathname); // /api/users
// Query params
console.log(url.searchParams.get("id")); // ?id=123
// Headers
console.log(req.headers.get("Content-Type"));
return new Response("OK");
},
});
```
## Body Parsing
```typescript
Bun.serve({
async fetch(req) {
// JSON
const json = await req.json();
// Form data
const form = await req.formData();
// Text
const text = await req.text();
// ArrayBuffer
const buffer = await req.arrayBuffer();
// Blob
const blob = await req.blob();
return new Response("Received");
},
});
```
## Response Types
```typescript
Bun.serve({
fetch(req) {
const url = new URL(req.url);
switch (url.pathname) {
case "/json":
return Response.json({ message: "Hello" });
case "/html":
return new Response("<h1>Hello</h1>", {
headers: { "Content-Type": "text/html" },
});
case "/redirect":
return Response.redirect("/new-location", 302);
case "/file":
return new Response(Bun.file("./image.png"));
case "/stream":
return new Response(
new ReadableStream({
start(controller) {
controller.enqueue("chunk1");
controller.enqueue("chunk2");
controller.close();
},
})
);
default:
return new Response("Not Found", { status: 404 });
}
},
});
```
## Simple Routing
```typescript
Bun.serve({
fetch(req) {
const url = new URL(req.url);
const path = url.pathname;
const method = req.method;
// Static routes
if (method === "GET" && path === "/") {
return new Response("Home");
}
if (method === "GET" && path === "/api/users") {
return Response.json([{ id: 1, name: "Alice" }]);
}
// Dynamic routes
const userMatch = path.match(/^\/api\/users\/(\d+)$/);
if (method === "GET" && userMatch) {
const userId = userMatch[1];
return Response.json({ id: userId });
}
// 404
return new Response("Not Found", { status: 404 });
},
});
```
## Error Handling
```typescript
Bun.serve({
fetch(req) {
try {
// Handle request
throw new Error("Something went wrong");
} catch (error) {
return new Response(
JSON.stringify({ error: error.message }),
{
status: 500,
headers: { "Content-Type": "application/json" }
}
);
}
},
error(error) {
// Global error handler
return new Response(`Error: ${error.message}`, { status: 500 });
},
});
```
## Server Options
```typescript
const server = Bun.serve({
port: 3000, // Default: 3000
hostname: "0.0.0.0", // Default: "0.0.0.0"
development: true, // Pretty errors in browser
// TLS/HTTPS
tls: {
key: Bun.file("./key.pem"),
cert: Bun.file("./cert.pem"),
},
// Unix socket
unix: "/tmp/my-socket.sock",
// Max request body size (default 128MB)
maxRequestBodySize: 1024 * 1024 * 10, // 10MB
fetch(req) {
return new Response("OK");
},
});
```
## Server Methods
```typescript
const server = Bun.serve({ ... });
// Server info
console.log(server.port); // 3000
console.log(server.hostname); // "0.0.0.0"
console.log(server.url); // URL object
// Stop server
server.stop();
// Reload with new config
server.reload({
fetch(req) {
return new Response("Updated!");
},
});
// Pending requests count
console.log(server.pendingRequests);
```
## Static Files
```typescript
Bun.serve({
fetch(req) {
const url = new URL(req.url);
// Serve static files from public/
if (url.pathname.startsWith("/static/")) {
const filePath = `./public${url.pathname.replace("/static", "")}`;
const file = Bun.file(filePath);
if (await file.exists()) {
return new Response(file);
}
return new Response("Not Found", { status: 404 });
}
return new Response("API");
},
});
```
## CORS
```typescript
function corsHeaders() {
return {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization",
};
}
Bun.serve({
fetch(req) {
// Handle preflight
if (req.method === "OPTIONS") {
return new Response(null, { headers: corsHeaders() });
}
// Add CORS headers to response
return new Response("OK", { headers: corsHeaders() });
},
});
```
## Common Errors
| Error | Cause | Fix |
|-------|-------|-----|
| `EADDRINUSE` | Port in use | Use different port or kill process |
| `Cannot read body` | Body already consumed | Read body once only |
| `CORS error` | Missing headers | Add CORS headers |
| `413 Payload Too Large` | Body exceeds limit | Increase maxRequestBodySize |
## When to Load References
Load `references/tls-config.md` when:
- HTTPS/TLS setup
- Certificate configuration
- mTLS authentication
Load `references/streaming.md` when:
- Server-sent events
- Streaming responses
- Chunked transfer encoding
This skill provides practical guidance and ready patterns for building high-performance HTTP servers with Bun.serve in TypeScript. It covers request parsing, response types, simple routing, error handling, static file serving, CORS, TLS, and useful server options. Use it to quickly implement REST APIs, fetch handlers, and streaming responses with Bun.
The skill demonstrates creating a Bun server via Bun.serve and supplying a fetch(req) handler that inspects the incoming Request object. It shows parsing method, path, query parameters, headers, and the body via json(), formData(), text(), arrayBuffer(), or blob(). Responses include JSON, HTML, redirects, files, and ReadableStream-based streaming. Additional patterns cover routing, global error handling, server options (port, hostname, TLS, unix sockets), and static file serving.
How do I handle CORS for browser requests?
Respond to OPTIONS preflight with appropriate Access-Control-Allow-* headers and attach the same headers to actual responses.
Why do I get 'Cannot read body' errors?
The body stream can be consumed only once. Parse it once (json/formData/text) and reuse the parsed value, or clone the request before consuming if needed.