Overview

Deploy Hono on Bun with native Bun.serve(). Best for high-performance applications using Bun.

Features

  • Native Bun.serve() for maximum performance
  • Security headers and CORS
  • Structured JSON logging
  • Health, ready, and live endpoints
  • Graceful shutdown
  • Memory and uptime reporting

Installation

npx hanma add hono-bun --framework hono

Dependencies

hono

Code

import { Hono } from "hono";
import { logger } from "hono/logger";
import { requestId } from "hono/request-id";
import { cors } from "hono/cors";
import { secureHeaders } from "hono/secure-headers";
import { timing } from "hono/timing";
import type { Context } from "hono";

// Environment configuration
const config = {
  port: Number(Bun.env.PORT) || 3000,
  env: Bun.env.NODE_ENV || "development",
  corsOrigins: Bun.env.CORS_ORIGINS?.split(",") || ["*"],
};

// Application type with custom variables
type AppEnv = {
  Variables: {
    requestId: string;
    startTime: number;
  };
};

const app = new Hono<AppEnv>();

// Security and observability middleware
app.use("*", secureHeaders());
app.use("*", timing());
app.use("*", requestId());
app.use("*", logger());
app.use("*", cors({
  origin: config.corsOrigins,
  allowMethods: ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"],
  allowHeaders: ["Content-Type", "Authorization", "X-Request-ID"],
  exposeHeaders: ["X-Request-ID", "X-Response-Time"],
  maxAge: 86400,
  credentials: true,
}));

// Request timing middleware
app.use("*", async (c, next) => {
  c.set("startTime", Date.now());
  await next();
});

// Health check endpoint
app.get("/health", (c) => {
  const uptime = process.uptime();
  const memory = process.memoryUsage();
  
  return c.json({
    status: "healthy",
    timestamp: new Date().toISOString(),
    runtime: "bun",
    version: Bun.version,
    uptime: {
      seconds: Math.floor(uptime),
      formatted: formatUptime(uptime),
    },
    memory: {
      heapUsed: formatBytes(memory.heapUsed),
      heapTotal: formatBytes(memory.heapTotal),
      rss: formatBytes(memory.rss),
    },
  });
});

// Readiness check for k8s/container orchestration
app.get("/ready", (c) => {
  // Add your readiness checks here (DB connection, cache, etc.)
  return c.json({ ready: true });
});

// Liveness check
app.get("/live", (c) => c.text("OK"));

// Example route
app.get("/", (c) => {
  return c.json({
    message: "Hello from Bun!",
    requestId: c.get("requestId"),
    environment: config.env,
  });
});

// 404 handler
app.notFound((c) => {
  return c.json(
    {
      success: false,
      error: {
        code: "NOT_FOUND",
        message: `Path ${c.req.method} ${c.req.path} not found`,
      },
      requestId: c.get("requestId"),
    },
    404
  );
});

// Global error handler
app.onError((err, c) => {
  const requestId = c.get("requestId") || "unknown";
  const status = "status" in err ? (err.status as number) : 500;
  
  // Log error with context
  console.error(JSON.stringify({
    level: "error",
    message: err.message,
    stack: err.stack,
    requestId,
    path: c.req.path,
    method: c.req.method,
    timestamp: new Date().toISOString(),
  }));
  
  return c.json(
    {
      success: false,
      error: {
        code: status === 500 ? "INTERNAL_ERROR" : "REQUEST_ERROR",
        message: config.env === "production" 
          ? "An unexpected error occurred" 
          : err.message,
      },
      requestId,
    },
    status
  );
});

// Utility functions
function formatUptime(seconds: number): string {
  const days = Math.floor(seconds / 86400);
  const hours = Math.floor((seconds % 86400) / 3600);
  const mins = Math.floor((seconds % 3600) / 60);
  return `${days}d ${hours}h ${mins}m`;
}

function formatBytes(bytes: number): string {
  const units = ["B", "KB", "MB", "GB"];
  let i = 0;
  while (bytes >= 1024 && i < units.length - 1) {
    bytes /= 1024;
    i++;
  }
  return `${bytes.toFixed(2)} ${units[i]}`;
}

// Server instance
let server: ReturnType<typeof Bun.serve> | null = null;

// Start server
export const startServer = () => {
  if (server) {
    console.log("Server already running");
    return;
  }

  server = Bun.serve({
    port: config.port,
    fetch: app.fetch,
    error(error) {
      console.error("Unhandled server error:", error);
      return new Response("Internal Server Error", { status: 500 });
    },
  });

  console.log(`Hono running on http://localhost:${server.port}`);
};

// Graceful shutdown
let isShuttingDown = false;

export const shutdown = (signal: string) => {
  if (isShuttingDown || !server) return;
  isShuttingDown = true;

  console.log(`${signal} received. Shutting down...`);
  
  server.stop();
  
  console.log("Server stopped");
  process.exit(0);
};

Usage

// Run with: bun run src/index.ts
// Health check: GET /health

Dependencies

Frequently Asked Questions

How do I install Bun Server?
Run the following command: npx hanma add hono-bun --framework hono
What dependencies are required?
This snippet requires: hono. Make sure to install them before using the snippet.
How do I use this snippet?
Copy the code and paste it into your project. The snippet will be saved to src/index.ts.
Can I customize this snippet?
Yes! All snippets are copy-paste code that you own. Feel free to modify them to fit your needs.
Does this work with other frameworks?
This snippet is designed for the specific framework. Check the other framework pages for equivalent implementations.