AWS Lambda — Run Code on Demand
AWS Lambda is a compute service that runs your code in response to events — an HTTP request, a file uploaded to S3, a message on a queue, a scheduled timer. You upload your function, configure how much memory it gets, and Lambda handles everything else: provisioning servers, patching the operating system, scaling up under load, and scaling back down to zero when traffic stops.
The core idea is simple: you pay only for the milliseconds your code actually runs, and you never touch a server. A function that handles 10,000 requests per day and a function that handles 10,000,000 look identical from your perspective — Lambda scales the underlying infrastructure automatically.
- Runtime: Node.js 20 (and many others — Python, Java, Go, .NET).
- Execution limit: Up to 15 minutes per invocation.
- Memory: 128 MB – 10,240 MB (CPU scales proportionally).
- Free Tier: 1 million requests and 400,000 GB-seconds of compute per month, every month.
A minimal Lambda function looks like this:
handler.mjs — ES module style (recommended)
export const handler = async (event) => {
console.log("Event received:", JSON.stringify(event, null, 2));
return {
statusCode: 200,
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ message: "Hello from Lambda!" }),
};
};DynamoDBDocumentClient) at module scope means they are created once and reused, not re-created on every request — cutting latency and cost.API Gateway — The Managed Front Door
API Gateway is a fully managed service that accepts HTTP requests from the internet and routes them to a backend — in our case, a Lambda function. It handles the heavy lifting that would otherwise fall on you: TLS termination, throttling, authentication hooks, CORS headers, request validation, and automatic scaling.
AWS offers two flavours relevant to Lambda:
| Type | Best for | Notable features |
|---|---|---|
| HTTP API | Most REST-style backends | Cheaper, lower latency, JWT authorizers, CORS built-in |
| REST API | Complex APIs needing full control | Request/response transforms, API keys, usage plans, caching |
In this course we use HTTP API — it is the recommended default for new Lambda-backed APIs. It is faster to configure, less expensive, and covers everything beginners need.
When API Gateway forwards a request to Lambda it wraps it in a proxy event object. Your handler reads event.httpMethod, event.path, event.queryStringParameters, and event.body (a JSON string you must parse). Your return value must be an API Gateway proxy response — a plain JavaScript object with statusCode, optional headers, and a body string.
body to be a string, not an object. Wrap it with JSON.stringify() every time, even for error responses.DynamoDB — Serverless NoSQL Database
DynamoDB is AWS's fully managed, key-value and document database. Like Lambda, it has no servers to patch, no capacity to pre-provision (in on-demand mode), and it scales from zero to millions of requests per second automatically. This makes it the natural database companion for Lambda.
Data is organized into tables. Every item (row) must have a partition key and optionally a sort key. Items in the same table can have different attributes — there is no fixed schema beyond the keys.
- On-demand capacity mode: Pay per request. No planning needed. Perfect for variable or unpredictable traffic.
- Provisioned capacity mode: Reserve read/write units in advance. More predictable cost at steady high throughput.
- Free Tier: 25 GB storage, 25 WCU, 25 RCU per month — permanently free.
We interact with DynamoDB from Lambda using the AWS SDK v3. The DynamoDBDocumentClient wrapper from @aws-sdk/lib-dynamodb handles marshalling JavaScript types to DynamoDB's wire format automatically:
db.mjs — client initialised at module scope
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient, GetCommand, PutCommand } from "@aws-sdk/lib-dynamodb";
const raw = new DynamoDBClient({ region: "us-east-1" });
export const db = DynamoDBDocumentClient.from(raw);
// Example: fetch one item by partition key
export const getItem = async (id) => {
const { Item } = await db.send(
new GetCommand({
TableName: process.env.TABLE_NAME,
Key: { id },
})
);
return Item ?? null;
};How They Work Together
Each service has a single, focused job. Together they form a complete, fully managed backend that needs no servers:
- A client (browser, mobile app, curl) sends an HTTP request.
- API Gateway receives it, validates it, and invokes your Lambda function.
- Lambda runs your business logic and queries DynamoDB.
- DynamoDB returns the data.
- Lambda builds the response and returns it to API Gateway.
- API Gateway forwards the HTTP response back to the client.
Service Roles at a Glance
Here is a quick reference mapping each service to its responsibility in the stack:
| Service | Category | Your job | AWS's job |
|---|---|---|---|
| API Gateway | Networking | Define routes, choose auth method | TLS, scaling, throttling, CORS, invoke Lambda |
| Lambda | Compute | Write handler code, set memory/timeout | Servers, OS patches, scaling, cold-start pooling |
| DynamoDB | Storage | Design table keys, write queries | Replication, backups, partitioning, scaling |
| IAM | Security | Attach least-privilege policy to Lambda role | Policy enforcement, credential rotation |
| CloudWatch | Observability | Add console.log statements |
Log storage, metrics dashboards, alarms |
What This Looks Like in SAM
AWS SAM (Serverless Application Model) is the Infrastructure-as-Code tool we use throughout this course. A complete serverless backend — API Gateway, Lambda, and DynamoDB — is described in a single template.yaml file. Here is the skeleton so the big picture is clear before we dive into each service:
template.yaml — SAM skeleton
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Globals:
Function:
Runtime: nodejs20.x
Environment:
Variables:
TABLE_NAME: !Ref ItemsTable
Resources:
# 1. The HTTP API — SAM creates it automatically when you add an Api event
ItemsFunction:
Type: AWS::Serverless::Function
Properties:
Handler: src/handler.handler
Events:
GetItems:
Type: HttpApi
Properties:
Path: /items
Method: GET
Policies:
- DynamoDBCrudPolicy:
TableName: !Ref ItemsTable
# 2. The DynamoDB table
ItemsTable:
Type: AWS::Serverless::SimpleTable
Properties:
PrimaryKey:
Name: id
Type: StringThat is the entire infrastructure definition. SAM expands this into the full CloudFormation stack, creates the API Gateway HTTP API, wires the Lambda trigger, and grants the function permission to read and write the table.
- Lambda runs your code on demand with zero server management. You pay per millisecond of execution, and it scales automatically from zero to millions of requests.
- API Gateway (HTTP API) is the secure, scalable front door. It handles TLS, throttling, CORS, and routing before handing the request off to Lambda as a proxy event.
- DynamoDB is the natural serverless database — fully managed, on-demand scaling, and billed per request rather than per provisioned server.
- The request lifecycle is: Client → API Gateway → Lambda → DynamoDB → Lambda → API Gateway → Client. Each hop is managed by AWS; you write only the Lambda handler code.
- IAM roles and CloudWatch Logs are always part of the picture even when not shown explicitly — SAM configures sensible defaults for both.