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.tsmkdir my-app
cd my-app
cdk init app -l typescript
yarn add hono
yarn add -D esbuild
mkdir lambda
touch lambda/index.tsmkdir my-app
cd my-app
cdk init app -l typescript
pnpm add hono
pnpm add -D esbuild
mkdir lambda
touch lambda/index.tsmkdir 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 deployThe 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_URLHandle 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
- Lambda@Edge - Run at CloudFront edge locations
- AWS CDK Documentation - Learn more about CDK
- AWS SDK for JavaScript - Integrate with AWS services