Skip to main content
The AWS Lambda adapter converts Hono applications into AWS Lambda handlers that work with API Gateway, ALB, Lambda Function URLs, and VPC Lattice.

Import

import { 
  handle, 
  streamHandle, 
  defaultIsContentTypeBinary, 
  getConnInfo 
} from 'hono/aws-lambda'
import type { 
  LambdaEvent, 
  APIGatewayProxyResult,
  ApiGatewayRequestContext,
  ApiGatewayRequestContextV2,
  ALBRequestContext,
  LambdaContext
} from 'hono/aws-lambda'

Functions

handle()

Converts a Hono application to an AWS Lambda handler. Accepts events from API Gateway (v1 and v2), Application Load Balancer (ALB), Lambda Function URLs, and VPC Lattice.
function handle<E extends Env, S extends Schema, BasePath extends string>(
  app: Hono<E, S, BasePath>,
  options?: HandleOptions
): LambdaHandler

Parameters

  • app - The Hono application instance
  • options - Optional configuration:
    • isContentTypeBinary - (contentType: string) => boolean - Function to determine if content should be base64 encoded

Returns

Lambda handler function compatible with API Gateway, ALB, and Function URLs.

Example

import { Hono } from 'hono'
import { handle } from 'hono/aws-lambda'

const app = new Hono()

app.get('/', (c) => c.text('Hello from Lambda!'))
app.post('/api/users', async (c) => {
  const body = await c.req.json()
  return c.json({ success: true, data: body })
})

app.get('/image', (c) => {
  // Binary responses are automatically base64 encoded
  return c.body(imageBuffer, 200, {
    'Content-Type': 'image/png'
  })
})

export const handler = handle(app)

Custom Binary Content Detection

import { handle, defaultIsContentTypeBinary } from 'hono/aws-lambda'

export const handler = handle(app, {
  isContentTypeBinary: (contentType) => {
    // Use default logic
    if (defaultIsContentTypeBinary(contentType)) {
      return true
    }
    // Add custom binary types
    return contentType.startsWith('image/') || 
           contentType === 'application/pdf' ||
           contentType === 'application/zip'
  }
})

streamHandle()

Creates a streaming Lambda handler that uses response streaming for better performance with large responses.
function streamHandle<E extends Env, S extends Schema, BasePath extends string>(
  app: Hono<E, S, BasePath>
): StreamingLambdaHandler
Streaming responses require Lambda function URLs or API Gateway HTTP APIs configured for streaming. This feature requires the AWS Lambda runtime to support response streaming.

Example

import { Hono } from 'hono'
import { streamHandle } from 'hono/aws-lambda'

const app = new Hono()

app.get('/large-data', async (c) => {
  // Stream large responses efficiently
  const stream = new ReadableStream({
    start(controller) {
      for (let i = 0; i < 10000; i++) {
        controller.enqueue(`Line ${i}\n`)
      }
      controller.close()
    }
  })
  return c.body(stream)
})

export const handler = streamHandle(app)

defaultIsContentTypeBinary()

Default function to determine if a content type should be base64 encoded.
function defaultIsContentTypeBinary(contentType: string): boolean

Returns

true if the content type is binary, false otherwise.

Logic

Returns false for:
  • text/* (text/plain, text/html, text/css, text/javascript, text/csv)
  • Content types containing json or xml (including application/json, application/xml, +json, +xml)
Returns true for all other content types.

getConnInfo()

Extracts connection information from AWS Lambda events.
function getConnInfo(c: Context): ConnInfo
Works with multiple event sources:
  • API Gateway v1 (REST API): requestContext.identity.sourceIp
  • API Gateway v2 (HTTP API/Function URLs): requestContext.http.sourceIp
  • ALB: Falls back to x-forwarded-for header

Returns

interface ConnInfo {
  remote: {
    address?: string  // Client IP address
  }
}

Example

import { Hono } from 'hono'
import { handle, getConnInfo } from 'hono/aws-lambda'

const app = new Hono()

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

app.get('/request-info', (c) => {
  const info = getConnInfo(c)
  const requestContext = c.env.requestContext
  
  return c.json({
    ip: info.remote.address,
    requestId: requestContext.requestId,
    stage: 'stage' in requestContext ? requestContext.stage : undefined
  })
})

export const handler = handle(app)

Types

LambdaEvent

Union type of all supported Lambda event types:
type LambdaEvent = 
  | APIGatewayProxyEvent      // API Gateway REST API (v1)
  | APIGatewayProxyEventV2    // API Gateway HTTP API (v2) / Function URLs
  | ALBProxyEvent             // Application Load Balancer
  | LatticeProxyEventV2       // VPC Lattice

APIGatewayProxyResult

Lambda response format for API Gateway:
type APIGatewayProxyResult = {
  statusCode: number
  statusDescription?: string
  body: string
  cookies?: string[]           // API Gateway v2 only
  isBase64Encoded: boolean
} & (WithHeaders | WithMultiValueHeaders)

Request Context Types

ApiGatewayRequestContext

API Gateway REST API (v1) request context:
interface ApiGatewayRequestContext {
  accountId: string
  apiId: string
  domainName: string
  httpMethod: string
  identity: Identity
  path: string
  requestId: string
  stage: string
  // ... additional fields
}

ApiGatewayRequestContextV2

API Gateway HTTP API (v2) and Function URLs request context:
interface ApiGatewayRequestContextV2 {
  accountId: string
  apiId: string
  domainName: string
  http: {
    method: string
    path: string
    protocol: string
    sourceIp: string
    userAgent: string
  }
  requestId: string
  routeKey: string
  stage: string
  // ... additional fields
}

ALBRequestContext

Application Load Balancer request context:
interface ALBRequestContext {
  elb: {
    targetGroupArn: string
  }
}

LambdaContext

AWS Lambda runtime context:
interface LambdaContext {
  callbackWaitsForEmptyEventLoop: boolean
  functionName: string
  functionVersion: string
  invokedFunctionArn: string
  memoryLimitInMB: string
  awsRequestId: string
  logGroupName: string
  logStreamName: string
  identity?: CognitoIdentity
  clientContext?: ClientContext
  getRemainingTimeInMillis(): number
}

Accessing Lambda Context

The Lambda event and context are available through c.env:
import { Hono } from 'hono'
import { handle } from 'hono/aws-lambda'
import type { LambdaEvent, LambdaContext } from 'hono/aws-lambda'

type Bindings = {
  event: LambdaEvent
  requestContext: ApiGatewayRequestContextV2
  lambdaContext: LambdaContext
}

const app = new Hono<{ Bindings: Bindings }>()

app.get('/lambda-info', (c) => {
  const { lambdaContext } = c.env
  
  return c.json({
    functionName: lambdaContext.functionName,
    requestId: lambdaContext.awsRequestId,
    remainingTime: lambdaContext.getRemainingTimeInMillis(),
    memoryLimit: lambdaContext.memoryLimitInMB
  })
})

export const handler = handle(app)

Platform-Specific Notes

Event Sources

The adapter automatically detects and handles:
  • API Gateway REST API (v1): Traditional REST APIs with resource-based routing
  • API Gateway HTTP API (v2): Lower latency, lower cost HTTP APIs
  • Lambda Function URLs: Direct HTTPS endpoints for Lambda functions
  • Application Load Balancer: ALB target integrations
  • VPC Lattice: Service mesh integrations

Binary Content

Binary responses are automatically base64 encoded based on:
  1. Content-Type header (via isContentTypeBinary option)
  2. Content-Encoding header (gzip, deflate, compress, br)

Headers

  • Single-value headers: Used by default and API Gateway v2
  • Multi-value headers: Used when the event includes multiValueHeaders

Cookies

  • API Gateway v2: Uses the cookies array in the response
  • API Gateway v1: Uses multiValueHeaders['set-cookie']
  • ALB: Depends on multi-value headers configuration

Deployment

Using AWS SAM

# template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31

Resources:
  HonoFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.handler
      Runtime: nodejs20.x
      Events:
        ApiEvent:
          Type: HttpApi
          Properties:
            Path: /{proxy+}
            Method: ANY

Using AWS CDK

import * as lambda from 'aws-cdk-lib/aws-lambda'
import * as apigateway from 'aws-cdk-lib/aws-apigatewayv2'
import { HttpLambdaIntegration } from 'aws-cdk-lib/aws-apigatewayv2-integrations'

const handler = new lambda.Function(this, 'HonoHandler', {
  runtime: lambda.Runtime.NODEJS_20_X,
  code: lambda.Code.fromAsset('dist'),
  handler: 'index.handler',
})

const httpApi = new apigateway.HttpApi(this, 'HonoApi', {
  defaultIntegration: new HttpLambdaIntegration('HonoIntegration', handler),
})

Using Serverless Framework

# serverless.yml
service: hono-lambda

provider:
  name: aws
  runtime: nodejs20.x

functions:
  api:
    handler: index.handler
    events:
      - httpApi:
          path: /{proxy+}
          method: ANY

See Also

Build docs developers (and LLMs) love