Overview

Deploy Hono to Vercel Edge. Best for Next.js projects needing edge API routes.

Features

  • Vercel Edge runtime
  • Edge caching with stale-while-revalidate
  • Region awareness
  • Security headers
  • Deployment URL context

Installation

npx hanma add hono-vercel --framework hono

Dependencies

hono

Code

import { Hono } from "hono";
import { handle } from "hono/vercel";
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 { cache } from "hono/cache";

export const config = {
  runtime: "edge",
};

// Environment configuration
const envConfig = {
  env: process.env.NODE_ENV || "development",
  corsOrigins: process.env.CORS_ORIGINS?.split(",") || ["*"],
  region: process.env.VERCEL_REGION || "unknown",
  deployment: process.env.VERCEL_URL || "localhost",
};

// Application type
type AppEnv = {
  Variables: {
    requestId: string;
  };
};

const app = new Hono<AppEnv>().basePath("/api");

// Security and observability middleware
app.use("*", secureHeaders());
app.use("*", timing());
app.use("*", requestId());
app.use("*", logger());
app.use("*", cors({
  origin: envConfig.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,
}));

// Cached health check
app.get(
  "/health",
  cache({
    cacheName: "health-check",
    cacheControl: "public, max-age=60",
  }),
  (c) => {
    return c.json({
      status: "healthy",
      timestamp: new Date().toISOString(),
      runtime: "vercel-edge",
      region: envConfig.region,
      deployment: envConfig.deployment,
      environment: envConfig.env,
    });
  }
);

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

// Example with caching
app.get(
  "/cached",
  cache({
    cacheName: "cached-response",
    cacheControl: "public, max-age=300, s-maxage=600, stale-while-revalidate=86400",
  }),
  (c) => {
    return c.json({
      data: "This response is cached at the edge",
      generatedAt: new Date().toISOString(),
      requestId: c.get("requestId"),
    });
  }
);

// 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;
  const isProduction = envConfig.env === "production";
  
  // Log error (visible in Vercel logs)
  console.error(JSON.stringify({
    level: "error",
    message: err.message,
    requestId,
    path: c.req.path,
    method: c.req.method,
    region: envConfig.region,
    timestamp: new Date().toISOString(),
  }));
  
  return c.json(
    {
      success: false,
      error: {
        code: status === 500 ? "INTERNAL_ERROR" : "REQUEST_ERROR",
        message: isProduction ? "An unexpected error occurred" : err.message,
      },
      requestId,
    },
    status
  );
});

export default handle(app);

Usage

// Deploy with: vercel
// API routes at /api/*

Dependencies

Frequently Asked Questions

How do I install Vercel Edge Functions?
Run the following command: npx hanma add hono-vercel --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 api/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.