Getting Started with AWS Lambda
This guide walks you through building a Zelt application on AWS Lambda from scratch.
Prerequisites
Additional requirements for AWS Lambda:
- An AWS account
- AWS CLI or SAM CLI
Installation
pnpm add @zeltjs/core @zeltjs/adapter-lambda
pnpm add -D @types/aws-lambda esbuild
Project Structure
my-app/
├── src/
│ ├── entry/
│ │ ├── controllers/ # HTTP endpoints
│ │ └── commands/ # CLI commands
│ ├── services/ # Business logic
│ ├── configs/ # Configuration classes
│ ├── app.ts # Application definition
│ ├── cli.ts # CLI entry point
│ └── main.ts # HTTP server entry point
├── package.json
└── tsconfig.json
| Directory | Purpose |
|---|---|
entry/ | External entry points (HTTP, CLI) |
services/ | Business logic, injected via DI |
configs/ | Environment variables and settings |
For AWS Lambda, also add template.yaml (SAM template) at the project root.
Hello World
Step 1: Create the Controller
Create src/entry/controllers/hello.controller.ts:
@Controller('/hello')
export class HelloController {
@Get('/:name')
greet(name = pathParam('name')) {
return { message: `Hello, ${name}!` };
}
}
Step 2: Create the Application
Create src/app.ts:
export const app = createApp([http({
controllers: [HelloController],
})]);
Step 3: Create the Lambda Handler
Create src/handler.ts:
const lambdaApp = await onLambda(app);
export const handler = lambdaApp.handler;
The onLambda() function prepares your app for the Lambda runtime. It returns:
handler— API Gateway v2 (HTTP API) handlerhandlerV1— API Gateway v1 (REST API) handlershutdown()— Gracefully shuts down the applicationget<T>(Class)— Resolves a service from the DI container
Step 4: Configure SAM Template
Create template.yaml:
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Globals:
Function:
Timeout: 30
Runtime: nodejs20.x
Resources:
HelloFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: dist/
Handler: handler.handler
Events:
Api:
Type: HttpApi
Properties:
Path: /{proxy+}
Method: ANY
Metadata:
BuildMethod: esbuild
BuildProperties:
Minify: true
Target: es2022
EntryPoints:
- src/handler.ts
Outputs:
ApiEndpoint:
Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com"
Step 5: Deploy
sam build
sam deploy --guided
API Gateway Versions
The adapter supports both API Gateway versions:
HTTP API (v2) — Recommended
export const handler = lambdaApp.handler;
REST API (v1)
export const handler = lambdaApp.handlerV1;
Warmup Option
By default, onLambda() uses lazy initialization (warmup: false) to minimize cold start time. Controllers are resolved on the first request.
For eager initialization:
const lambdaApp = await onLambda(app, { warmup: true });
| Option | Behavior | Use Case |
|---|---|---|
warmup: false (default) | Controllers resolved on first request | Optimized cold starts |
warmup: true | All controllers resolved at initialization | Provisioned concurrency |
Binary Responses
The adapter automatically handles binary responses (images, audio, video, octet-stream) by encoding them as base64.
@Controller('/files')
export class FileController {
@Get('/image')
getImage() {
const imageBuffer = new Uint8Array([/* ... */]);
return response()
.header('Content-Type', 'image/png')
.body(imageBuffer);
}
}
What's Next?
- Controllers — Route handling and HTTP methods
- Services — Business logic and dependency injection
- Configuration — Environment variables and secrets