Skip to Content
deploymentAws Lambda

Last Updated: 3/9/2026


AWS Lambda

AWS Lambda  is Amazon’s serverless compute service that runs your code in response to events and automatically manages the underlying compute resources. It integrates seamlessly with the AWS ecosystem.

Hono works on AWS Lambda with Node.js 18+ runtime.

Quick Start

The easiest way to deploy Hono to AWS Lambda is using AWS CDK  (Cloud Development Kit).

Setup with AWS CDK

1. Initialize Project

::: code-group

mkdir my-app cd my-app cdk init app -l typescript npm install hono npm install -D esbuild mkdir lambda touch lambda/index.ts
mkdir my-app cd my-app cdk init app -l typescript yarn add hono yarn add -D esbuild mkdir lambda touch lambda/index.ts
mkdir my-app cd my-app cdk init app -l typescript pnpm add hono pnpm add -D esbuild mkdir lambda touch lambda/index.ts
mkdir my-app cd my-app cdk init app -l typescript bun add hono bun add -D esbuild mkdir lambda touch lambda/index.ts

:::

2. Write Your Application

Edit lambda/index.ts:

import { Hono } from 'hono' import { handle } from 'hono/aws-lambda' const app = new Hono() app.get('/', (c) => { return c.text('Hello AWS Lambda!') }) app.get('/api/hello', (c) => { return c.json({ message: 'Hello from Lambda', region: process.env.AWS_REGION, }) }) export const handler = handle(app)

Important: Export your handler as export const handler = handle(app)

3. Configure CDK Stack

Edit lib/my-app-stack.ts:

import * as cdk from 'aws-cdk-lib' import { Construct } from 'constructs' import * as lambda from 'aws-cdk-lib/aws-lambda' import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs' export class MyAppStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props) // Create Lambda function const fn = new NodejsFunction(this, 'HonoLambda', { entry: 'lambda/index.ts', handler: 'handler', runtime: lambda.Runtime.NODEJS_22_X, timeout: cdk.Duration.seconds(30), memorySize: 512, }) // Create Function URL const fnUrl = fn.addFunctionUrl({ authType: lambda.FunctionUrlAuthType.NONE, }) // Output the URL new cdk.CfnOutput(this, 'FunctionUrl', { value: fnUrl.url, }) } }

4. Deploy

Deploy your application:

cdk deploy

The function URL will be displayed in the output.

Environment Variables

Set environment variables in your CDK stack:

const fn = new NodejsFunction(this, 'HonoLambda', { entry: 'lambda/index.ts', handler: 'handler', runtime: lambda.Runtime.NODEJS_22_X, environment: { API_KEY: 'your-api-key', DATABASE_URL: 'postgresql://...', }, })

Access them in your code:

app.get('/config', (c) => { return c.json({ apiKey: process.env.API_KEY, region: process.env.AWS_REGION, }) })

Accessing Lambda Context

Access AWS Lambda event and context objects:

import { Hono } from 'hono' import { handle } from 'hono/aws-lambda' import type { LambdaEvent, LambdaContext } from 'hono/aws-lambda' type Bindings = { event: LambdaEvent lambdaContext: LambdaContext } const app = new Hono<{ Bindings: Bindings }>() app.get('/lambda-info', (c) => { return c.json({ requestId: c.env.lambdaContext.awsRequestId, functionName: c.env.lambdaContext.functionName, remainingTime: c.env.lambdaContext.getRemainingTimeInMillis(), isBase64Encoded: c.env.event.isBase64Encoded, }) }) export const handler = handle(app)

Request Context

Access API Gateway request context:

import type { LambdaEvent } from 'hono/aws-lambda' type Bindings = { event: LambdaEvent } const app = new Hono<{ Bindings: Bindings }>() app.get('/request-info', (c) => { const requestContext = c.env.event.requestContext return c.json({ requestId: requestContext.requestId, apiId: requestContext.apiId, stage: requestContext.stage, sourceIp: requestContext.identity?.sourceIp, }) })

Binary Data

Lambda requires base64 encoding for binary responses. Hono handles this automatically:

app.get('/image', async (c) => { const imageBuffer = await fetchImage() c.header('Content-Type', 'image/png') // Binary content type return c.body(imageBuffer) // Automatically base64 encoded }) app.get('/pdf', async (c) => { const pdfBuffer = await generatePDF() c.header('Content-Type', 'application/pdf') return c.body(pdfBuffer) })

Response Streaming

Enable Lambda response streaming  for large responses:

Configure Streaming in CDK

const fn = new NodejsFunction(this, 'HonoLambda', { entry: 'lambda/index.ts', handler: 'handler', runtime: lambda.Runtime.NODEJS_22_X, }) const fnUrl = fn.addFunctionUrl({ authType: lambda.FunctionUrlAuthType.NONE, invokeMode: lambda.InvokeMode.RESPONSE_STREAM, // Enable streaming })

Use streamHandle

import { Hono } from 'hono' import { streamHandle } from 'hono/aws-lambda' import { streamText } from 'hono/streaming' const app = new Hono() app.get('/stream', (c) => { return streamText(c, async (stream) => { for (let i = 0; i < 100; i++) { await stream.writeln(`Line ${i}`) await stream.sleep(100) } }) }) // Use streamHandle instead of handle export const handler = streamHandle(app)

Integration with AWS Services

DynamoDB

import { DynamoDBClient } from '@aws-sdk/client-dynamodb' import { DynamoDBDocumentClient, GetCommand } from '@aws-sdk/lib-dynamodb' const client = new DynamoDBClient({}) const docClient = DynamoDBDocumentClient.from(client) app.get('/users/:id', async (c) => { const id = c.req.param('id') const result = await docClient.send( new GetCommand({ TableName: 'Users', Key: { id }, }) ) return c.json(result.Item) })

S3

import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3' const s3 = new S3Client({}) app.post('/upload', async (c) => { const body = await c.req.arrayBuffer() await s3.send( new PutObjectCommand({ Bucket: 'my-bucket', Key: 'file.txt', Body: Buffer.from(body), }) ) return c.json({ message: 'Uploaded successfully' }) })

SQS

import { SQSClient, SendMessageCommand } from '@aws-sdk/client-sqs' const sqs = new SQSClient({}) app.post('/queue', async (c) => { const data = await c.req.json() await sqs.send( new SendMessageCommand({ QueueUrl: process.env.QUEUE_URL, MessageBody: JSON.stringify(data), }) ) return c.json({ message: 'Queued' }) })

API Gateway Integration

REST API

Integrate with API Gateway REST API:

import * as apigateway from 'aws-cdk-lib/aws-apigateway' const api = new apigateway.LambdaRestApi(this, 'HonoApi', { handler: fn, proxy: true, })

HTTP API

Use HTTP API for lower cost and latency:

import * as apigatewayv2 from 'aws-cdk-lib/aws-apigatewayv2' import * as integrations from 'aws-cdk-lib/aws-apigatewayv2-integrations' const httpApi = new apigatewayv2.HttpApi(this, 'HonoHttpApi') httpApi.addRoutes({ path: '/{proxy+}', methods: [apigatewayv2.HttpMethod.ANY], integration: new integrations.HttpLambdaIntegration( 'HonoIntegration', fn ), })

VPC Access

Access resources in a VPC:

import * as ec2 from 'aws-cdk-lib/aws-ec2' const vpc = ec2.Vpc.fromLookup(this, 'VPC', { vpcId: 'vpc-xxxxx', }) const fn = new NodejsFunction(this, 'HonoLambda', { entry: 'lambda/index.ts', handler: 'handler', runtime: lambda.Runtime.NODEJS_22_X, vpc, vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, }, })

Best Practices

Optimize Cold Starts

Minimize cold start time:

// ✅ Import only what you need import { Hono } from 'hono' import { handle } from 'hono/aws-lambda' // ❌ Avoid heavy imports at top level // import * as AWS from 'aws-sdk' // Large package // ✅ Lazy load when needed app.get('/heavy', async (c) => { const AWS = await import('aws-sdk') // Use AWS SDK })

Use Environment Variables

// ❌ Don't hardcode const dbUrl = 'postgresql://user:pass@host/db' // ✅ Use environment variables const dbUrl = process.env.DATABASE_URL

Handle Errors

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

Set Appropriate Timeout

const fn = new NodejsFunction(this, 'HonoLambda', { // ... timeout: cdk.Duration.seconds(30), // Max 900s memorySize: 1024, // More memory = more CPU })

What’s Next