Skip to main content
The Vercel adapter provides utilities for running Hono applications on Vercel’s Edge Runtime and Serverless Functions.

Import

import { handle, getConnInfo } from 'hono/vercel'

Functions

handle()

Converts a Hono application into a Vercel request handler.
function handle(
  app: Hono
): (req: Request) => Response | Promise<Response>

Parameters

  • app - The Hono application instance

Returns

A request handler function that can be exported as the default export.

Example

import { Hono } from 'hono'
import { handle } from 'hono/vercel'

const app = new Hono()

app.get('/', (c) => {
  return c.text('Hello from Vercel!')
})

app.get('/api/users/:id', (c) => {
  const id = c.req.param('id')
  return c.json({ id, name: 'John Doe' })
})

app.post('/api/data', async (c) => {
  const body = await c.req.json()
  return c.json({ success: true, data: body })
})

export default handle(app)

getConnInfo()

Extracts connection information from the Vercel request.
function getConnInfo(c: Context): ConnInfo

Returns

interface ConnInfo {
  remote: {
    address?: string  // Client IP from x-real-ip header
  }
}

Example

import { Hono } from 'hono'
import { handle, getConnInfo } from 'hono/vercel'

const app = new Hono()

app.get('/', (c) => {
  const info = getConnInfo(c)
  return c.text(`Your IP: ${info.remote.address}`)
})

app.get('/api/location', (c) => {
  const info = getConnInfo(c)
  const country = c.req.header('x-vercel-ip-country')
  const city = c.req.header('x-vercel-ip-city')
  
  return c.json({
    ip: info.remote.address,
    country,
    city
  })
})

export default handle(app)

Platform-Specific Notes

Edge Runtime vs Serverless

Vercel supports two runtime environments:
  • Edge Runtime: Runs on Vercel’s Edge Network, closer to users for lower latency
  • Serverless Functions: Traditional serverless functions with full Node.js compatibility
The adapter works with both. Configure the runtime in your vercel.json:
{
  "functions": {
    "api/**/*.ts": {
      "runtime": "edge"
    }
  }
}

Request Headers

Vercel provides additional headers:
  • x-real-ip - Client’s real IP address
  • x-forwarded-for - Proxy chain
  • x-vercel-ip-country - Country code (e.g., “US”)
  • x-vercel-ip-city - City name (e.g., “San Francisco”)
  • x-vercel-ip-country-region - Region code (e.g., “CA”)
  • x-vercel-ip-latitude - Latitude
  • x-vercel-ip-longitude - Longitude

File Structure

For file-based routing in the api/ directory:
project/
├── api/
│   ├── index.ts          # Handles /api
│   ├── hello.ts          # Handles /api/hello
│   └── users/
│       └── [id].ts       # Handles /api/users/:id
└── vercel.json

Example with Dynamic Routes

// api/users/[id].ts
import { Hono } from 'hono'
import { handle } from 'hono/vercel'

const app = new Hono()

app.get('/api/users/:id', (c) => {
  const id = c.req.param('id')
  return c.json({ id, name: 'User ' + id })
})

export default handle(app)

Catch-All Routes

For a single handler that handles all routes:
// api/[...route].ts
import { Hono } from 'hono'
import { handle } from 'hono/vercel'

const app = new Hono()

app.get('/api/*', (c) => {
  return c.json({ path: c.req.path })
})

app.post('/api/data', async (c) => {
  const body = await c.req.json()
  return c.json(body)
})

export default handle(app)

Environment Variables

Access Vercel environment variables directly:
import { Hono } from 'hono'
import { handle } from 'hono/vercel'

const app = new Hono()

app.get('/api/config', (c) => {
  return c.json({
    nodeEnv: process.env.NODE_ENV,
    vercelEnv: process.env.VERCEL_ENV, // 'production', 'preview', or 'development'
    vercelUrl: process.env.VERCEL_URL,
  })
})

export default handle(app)

Configuration

vercel.json

{
  "functions": {
    "api/**/*.ts": {
      "runtime": "edge",
      "maxDuration": 10
    }
  },
  "rewrites": [
    {
      "source": "/(.*)",
      "destination": "/api"
    }
  ]
}

TypeScript Configuration

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "lib": ["ES2022"],
    "moduleResolution": "bundler",
    "types": ["@vercel/node"]
  }
}

Deployment

Using Vercel CLI

# Install Vercel CLI
npm i -g vercel

# Deploy
vercel

# Deploy to production
vercel --prod

Using Git Integration

Connect your repository to Vercel:
  1. Import your Git repository at vercel.com/new
  2. Configure build settings (if needed)
  3. Deploy automatically on every push

Build Configuration

{
  "buildCommand": "npm run build",
  "outputDirectory": "dist",
  "installCommand": "npm install"
}

Complete Example

// api/index.ts
import { Hono } from 'hono'
import { handle, getConnInfo } from 'hono/vercel'
import { cors } from 'hono/cors'
import { logger } from 'hono/logger'

const app = new Hono()

app.use('*', cors())
app.use('*', logger())

app.get('/', (c) => {
  const info = getConnInfo(c)
  return c.json({ 
    message: 'Hello from Vercel!',
    ip: info.remote.address,
    country: c.req.header('x-vercel-ip-country')
  })
})

app.get('/api/hello/:name', (c) => {
  const name = c.req.param('name')
  return c.json({ message: `Hello, ${name}!` })
})

app.post('/api/echo', async (c) => {
  const body = await c.req.json()
  return c.json(body)
})

app.notFound((c) => {
  return c.json({ error: 'Not Found' }, 404)
})

app.onError((err, c) => {
  console.error(err)
  return c.json({ error: 'Internal Server Error' }, 500)
})

export default handle(app)

See Also

Build docs developers (and LLMs) love