Serverless#
Serverless is managed compute, scaled by the platform, billed per execution. The operator never sees the underlying machines, which is the point and the trade-off. A function fires on a trigger, runs, and goes away; a redirector, a webhook, a scheduled collector, or a defensive automation lands and disappears without leaving a fleet to maintain.
Serverless from the infrastructure angle: where it fits in a DevOps stack, what operational properties it has, and what trade-offs make it the right (or wrong) choice for a given mission. For the architectural view, see Serverless.
flowchart LR
subgraph Triggers
HTTP[HTTP]
Sched[Schedule]
Q[Queue]
Obj[Storage Event]
Pub[Pub-Sub]
end
HTTP --> F1[Function]
Sched --> F2[Function]
Q --> F3[Function]
Obj --> F4[Function]
Pub --> F5[Function]
F1 --> DB[(Managed DB)]
F2 --> Bucket[(Object Storage)]
F3 --> Cache[(Managed Cache)]
F4 --> Out[Other Service]
F5 --> Topic[(Topic)]
Forms of Serverless#
The five flavors an operator may meet. FaaS for one-function triggers; container-based serverless for whole apps; edge runtimes for sub-10 ms cold starts; backend-as-a-service for managed primitives; workflow-as-a-service for durable orchestration. Each fits a different shape of workload.
FaaS, AWS Lambda, Google Cloud Functions, Azure Functions. One function, one trigger; runs in a sandboxed lightweight VM.
Container-based, AWS Fargate, Cloud Run, Azure Container Apps. Bring an OCI image; the platform schedules and scales it.
Edge runtimes, Cloudflare Workers, Vercel Edge Functions, Deno Deploy, AWS Lambda@Edge. V8 isolates or tiny WASM runtimes; sub-10 ms cold starts.
Backend-as-a-Service, Firebase, Supabase, Hasura. Managed primitives that replace code for common cases.
Workflow-as-a-Service, AWS Step Functions, GCP Workflows, Temporal Cloud. Durable orchestration on managed compute.
Function Topologies#
A single function is rarely the whole job. The shapes below cover how functions chain into composed workflows; each one trades control for coupling.
Sequential chain#
The simplest composition. One function’s output becomes the next function’s input, end to end. Easy to reason about; latency is the sum of every step; one failure breaks the chain unless every function is idempotent and the caller retries.
flowchart LR
T[trigger] --> A[fn A]
A --> B[fn B]
B --> C[fn C]
C --> OUT[(result)]
Fan-out#
One trigger, many parallel workers. Used when the work is embarrassingly parallel, fetching N URLs, scoring N candidates, hashing N files. Latency is the slowest worker.
flowchart LR
T[trigger] --> A[fn A: split]
A --> W1[fn W1]
A --> W2[fn W2]
A --> W3[fn W3]
W1 --> SINK[(sink)]
W2 --> SINK
W3 --> SINK
Fan-in (aggregator)#
Many producers, one consumer. The aggregator merges results, deduplicates, and emits the combined output. Backed by a queue or a stream so the aggregator never blocks producers.
flowchart LR
P1[producer 1] --> Q[(queue / stream)]
P2[producer 2] --> Q
P3[producer 3] --> Q
Q --> AGG[fn aggregator]
AGG --> OUT[(result)]
Map-reduce#
Fan-out plus fan-in. A coordinator splits work; mappers process shards in parallel; a reducer combines the partial results. The canonical batch shape; works for ad-hoc data pipelines and scheduled rollups.
flowchart LR
IN[(input)] --> SPL[fn splitter]
SPL --> M1[map 1]
SPL --> M2[map 2]
SPL --> M3[map 3]
M1 --> RED[reduce]
M2 --> RED
M3 --> RED
RED --> OUT[(output)]
Event bus / pub-sub#
Producer functions emit events to a bus; any number of consumer functions subscribe. Producers and consumers do not know each other; adding a consumer never touches a producer. The default shape for telemetry, audit, and any workflow where the write rate exceeds the read rate.
flowchart LR
P1[producer A] --> BUS{{event bus}}
P2[producer B] --> BUS
BUS --> C1[fn consumer X]
BUS --> C2[fn consumer Y]
BUS --> C3[fn consumer Z]
Choreography#
Each function reacts to events emitted by the previous step and emits its own event when done. No central orchestrator; the flow emerges from event subscriptions. Loosely coupled but the end-to-end shape lives implicitly in the subscriptions, hard to inspect.
flowchart LR
ORDER[fn order] -->|OrderPlaced| BUS{{event bus}}
BUS --> PAY[fn payment]
PAY -->|PaymentCaptured| BUS
BUS --> INV[fn inventory]
INV -->|StockReserved| BUS
BUS --> SHIP[fn shipping]
Orchestration via state machine#
A workflow service (AWS Step Functions, GCP Workflows, Azure Logic Apps, Temporal) drives the sequence explicitly. State machine definition declares branches, retries, parallel tasks, and waits; each step is a function. The shape is auditable, testable, and survives long-running waits (hours, days).
flowchart LR
START([start]) --> VAL[fn validate]
VAL --> CHK{ok?}
CHK -->|no| ERR([reject])
CHK -->|yes| PAR{parallel}
PAR --> P1[fn fraud-check]
PAR --> P2[fn inventory]
P1 --> JOIN((join))
P2 --> JOIN
JOIN --> SHIP[fn ship]
SHIP --> NOTIFY[fn notify]
NOTIFY --> END([done])
Saga (compensation)#
A long-running transaction split into local steps; each with a compensating action that undoes its effect on failure. Used when the workflow crosses systems that cannot share a transaction (payment provider plus inventory plus shipping). Either choreography- or orchestration-driven.
flowchart LR
S1[fn reserve stock] -->|ok| S2[fn charge card]
S2 -->|ok| S3[fn create shipment]
S3 -->|ok| OK([commit])
S3 -.fail.-> R3[fn refund card] --> R2[fn release stock] --> FAIL([compensated])
S2 -.fail.-> R2
S1 -.fail.-> FAIL
Pipes-and-filters#
Streaming version of the sequential chain. A producer writes records to a stream; one or more functions transform records in flight; a sink writes the final form. Each filter is independently scaled by stream lag.
flowchart LR
SRC[(stream)] --> F1[fn filter]
F1 --> F2[fn enrich]
F2 --> F3[fn transform]
F3 --> DST[(sink)]
Properties That Matter#
The operational characteristics that distinguish serverless from always-on compute. Scale-to-zero, automatic scale-up, no fleet operations, per-execution billing, cold-start tax, runtime constraints, and stateless-by-design; each shapes which workloads fit and which don’t.
Scale to zero, no idle cost.
Auto-scale up, platform handles spikes.
No fleet to operate, no patching, no autoscaling configuration, no node management.
Per-execution pricing, proportional to use; can surprise under sustained load.
Cold starts, first request after idle pays a startup tax.
Runtime constraints, max execution time (15 min Lambda, more for container-based), memory, payload size, no local filesystem of consequence.
Stateless by design, state goes in managed services.
Cold Starts in Practice#
Runtime |
Typical cold start (after idle) |
|---|---|
Lambda Node.js / Python |
100-500 ms |
Lambda Java / .NET |
500 ms - 3 s |
Lambda Go / Rust |
~50-150 ms |
Lambda + provisioned conc. |
sub-50 ms (paid pre-warming) |
Cloud Run (container) |
500 ms - 2 s |
Edge runtimes (Workers etc.) |
<10 ms |
Mitigations: smaller deployment packages, faster runtimes (Go / Rust / Bun), provisioned concurrency, edge runtimes, “warmer” pings (a ritual that’s mostly been replaced by provisioned concurrency).
Where Serverless Wins#
The shapes of workload that serverless was built for. Spiky and event-driven, glue between cloud services, low-traffic APIs, edge-near work, periodic jobs, and internal tools that can’t justify a server; each plays to the no-idle-cost story.
Spiky / event-driven workloads, Lambda triggered by S3 uploads, queue messages, schedule.
Glue between cloud services, thin code with managed primitives doing the heavy lifting.
Low-traffic APIs, the no-idle-cost story dominates.
Edge-near work, A/B routing, personalization, auth middleware close to users.
Periodic jobs, cron without a host.
Internal tools that don’t justify a server.
Where Serverless Loses#
The mirror image. Sustained high traffic loses to always-on containers; long-running computations bump against time limits; heavy startup costs hurt latency; state-heavy workloads strain the surrounding services; hard real-time fights cold starts; and vendor lock-in is real.
Sustained high-traffic workloads, always-on containers are usually cheaper.
Long-running computations, function time limits bite.
Heavy startup costs, JVM / .NET in a latency-sensitive path.
State-heavy workloads, the surrounding managed services need to scale alongside.
Hard-real-time, predictable latency is hard with cold starts.
Local dev parity, emulators are imperfect.
Vendor lock-in, function signatures, triggers, IAM, observability are all platform-specific.
Serverless and the Rest of the Stack#
Serverless is not a separate world from the rest of DevOps:
IaC still applies, Terraform / CDK / SAM provision functions.
CI/CD still applies, build artifact → deploy via SAM / CDK / Pulumi / Terraform.
Observability still applies, platform integrations (CloudWatch Logs, X-Ray) plus OpenTelemetry.
Security still applies, IAM scoping, secrets management, least privilege.
GitOps, frameworks like SST / Encore / Architect provide Git-driven deploy semantics.
Frameworks#
The frameworks an operator picks among when authoring serverless applications. AWS SAM and CDK lead inside AWS; Serverless Framework is the multi-cloud abstraction; SST is the modern TypeScript-first option; Knative and OpenFaaS self-host the model on Kubernetes.
AWS Lambda + SAM / AWS CDK, AWS-native.
Serverless Framework, multi-cloud abstraction (declining a bit in favor of CDK / SAM / SST).
SST, TypeScript-first serverless framework.
Encore, Go / TypeScript framework with built-in infra.
OpenFaaS / Knative / Fission, run serverless on your own Kubernetes.
Wrangler, Cloudflare Workers tooling.
For greenfield serverless work in 2026, SST (TypeScript) and CDK (any of its languages) are the strongest defaults.
Cost Model#
A useful mental model for steady-state cost:
FaaS,
per-request charge + memory × duration. Sub-second responses are cheap; minute-long ones aren’t.Container serverless, per-second-while-running. Cheaper for steady traffic.
Always-on containers, pay for the always-on capacity.
The break-even between Lambda and Fargate / Cloud Run is usually around 10-30% utilization. Above that, containers are cheaper.
Operational Cautions#
The traps that catch teams running serverless in production. Account-level concurrency throttles surprise; connection storms drown databases without proxies; async trigger retries demand idempotent design; logs and traces spread thinly across many short-lived processes.
Concurrency limits, AWS Lambda has account-level reserved concurrency; can throttle unexpectedly.
Connection storms to databases, thousands of warm function instances all open DB connections; use proxies (RDS Proxy, PgBouncer) or pools.
Retries on async triggers, not always idempotent; design for at-least-once delivery.
Logs and traces, spread across many short-lived processes; invest in structured logging and tracing early.
The 2026 Take#
Serverless settled into a clear sweet spot:
For event-driven, glue, edge, and low-traffic, the right default.
For full applications, container-based serverless (Cloud Run, Fargate, Container Apps) is often the right middle ground.
For high-traffic core services, always-on containers on Kubernetes (or simpler PaaS) usually win on cost and operational parity.
The “serverless or Kubernetes” debate has mostly been resolved into “both, in the right places”.
See Also#
Serverless, the architectural angle.
Containers, the boundary case.
Cloud, where serverless services live.