Serverless Architecture Patterns

Serverless computing runs your code without you managing servers — the provider handles provisioning, scaling, and patching, and you pay only for the compute you actually use. It's a great fit for event-driven, spiky, or unpredictable workloads, but designing well for it means thinking differently: small focused functions, loose coupling through events, and an eye on cold starts and cost.

This guide covers the patterns that hold up in production. The recurring theme: functions are composable building blocks, and your architecture is mostly about how events flow between them.

TL;DR

Quick Example

A focused handler does one thing — parse, validate, save — and nothing else:

Core Concepts

Serverless characteristics

Common triggers

Cold Starts

A "cold start" is the latency penalty when the platform spins up a new execution environment. Mitigate it by doing expensive setup once, outside the handler, and keeping critical paths warm:

Event-Driven Architecture

Decouple services by publishing events rather than calling each other directly. Producers don't know or care who consumes:

Common Patterns

Fan-out

One event triggers many independent consumers, processing in parallel:

Aggregator

Combine results from several functions into one response:

Orchestration (Step Functions)

For multi-step workflows with branching and error handling, use a state machine instead of chaining functions manually:

Cost Considerations

Cost scales with invocations × duration × memory, so right-sizing matters — and more memory can be cheaper when it makes functions finish faster:

Other levers: batch processing where possible, minimize cold starts, and use reserved/provisioned capacity for predictable, steady loads.

Best Practices

Common Mistakes

One function doing everything

Heavy setup inside the handler

FAQ

What is a cold start and how bad is it?

It's the extra latency when the platform creates a fresh execution environment for your function (loading the runtime and your code). It ranges from tens of milliseconds to a few seconds depending on runtime and package size. Mitigate with module-level initialization, smaller deployment packages, and provisioned concurrency for latency-sensitive paths.

When should I NOT use serverless?

Long-running jobs (beyond the platform timeout), workloads needing persistent connections or custom networking, very high steady-state traffic (where reserved capacity is cheaper), and anything requiring strict, low-latency database connection pooling. For those, containers or VMs often fit better — see Cloud Computing.

How do I handle database connections from serverless?

Connection exhaustion is the classic trap: thousands of concurrent functions each opening a connection overwhelms the database. Use a connection proxy/pooler (RDS Proxy, PgBouncer, serverless drivers), keep clients initialized at module scope, and cap concurrency. See Database Replication and Caching.

Should I orchestrate functions in code or with a state machine?

For simple sequential calls, code is fine. For multi-step workflows with retries, branching, parallelism, and human-readable status, use an orchestration service (Step Functions, Cloud Workflows). It externalizes the control flow, gives you visibility, and handles failure transitions declaratively.

Related Topics

References