About bun-http-server
bun-http-server is a skill for building HTTP servers with Bun. It covers request handling, routing, response types, static files, CORS, and server configuration.
Key features
- 01Create servers with Bun.serve()
- 02Handle request methods and bodies
- 03Define routes and dynamic parameters
- 04Return JSON and other responses
- 05Serve static files
- 06Configure TLS and CORS
Use cases
- 01Build a small HTTP API
- 02Parse JSON or form submissions
- 03Serve static assets
- 04Configure HTTPS or streaming responses
Install
Copy the command and run it in a terminal.
$
npx skills add https:/ / github.com/ secondsky/ claude-skills --skill bun-http-serverAfter installing, type/bun-http-serverin Claude Code to confirm it loaded.
Details
From the project READMEBun HTTP Server
Bun has a built-in high-performance HTTP server via Bun.serve().
Quick Start
const server = Bun.serve({
port: 3000,
fetch(req) {
return new Response("Hello World!");
},
});
console.log(`Server running at http://localhost:${server.port}`);
Request Handling
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
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
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
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
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
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
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 (Bun 1.2+: returns a Promise — await it to flush in-flight
// requests; calling it without await may not drain connections).
await server.stop();
// Reload with new config
server.reload({
fetch(req) {
return new Response("Updated!");
},
});
// Pending requests count
console.log(server.pendingRequests);
Routing with routes (Bun 1.2+)
The examples above use the classic fetch(req) handler with manual URL
parsing, which still works. As of Bun 1.2, the canonical way to declare
route maps is the routes option, with dynamic params available on
req.params:
Bun.serve({
routes: {
"/api/users": {
GET: () => Response.json([{ id: 1, name: "Alice" }]),
POST: async (req) => Response.json(await req.json(), { status: 201 }),
},
"/api/users/:id": (req) => {
const { id } = req.params;
return Response.json({ id });
},
},
fetch(req) {
return new Response("Not Found", { status: 404 });
},
});
Use routes for new code; keep fetch as a fallback for unmatched paths.
Static Files
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
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
Comments
Markdown supported