The execution model
You upload a handler; the platform creates an isolated execution environment per concurrent request and destroys idle ones. You pay per invocation and per GB-second of duration, with zero cost at zero traffic — the strongest argument for spiky or unpredictable workloads.
Cold starts and state
A first request to a fresh environment pays initialisation. Keep packages small, initialise clients outside the handler so they are reused, and use provisioned concurrency for latency-critical paths. Functions are stateless: persist anything durable externally.
Where it stops fitting
Execution timeouts, payload caps and limited local storage rule out long jobs. Steady, high-volume traffic is usually cheaper on containers, and heavy fan-out can overwhelm downstream databases unless you cap concurrency or pool connections through a proxy.
import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3";
// Created once per environment, reused across warm invocations.
const s3 = new S3Client({});
export const handler = async (event: { key: string }) => {
const out = await s3.send(new GetObjectCommand({ Bucket: "reports", Key: event.key }));
return { statusCode: 200, body: await out.Body!.transformToString() };
};