Code that waits for nothing
- The trigger. An HTTP request, a new file in a bucket, a queue message, a timer. No event means no process, and no process means nothing to pay for.
- The environment. The platform starts a sandbox holding your runtime and code, passes it the event, and may keep it warm briefly in case another arrives. AWS Lambda, Cloudflare Workers, Azure Functions and Google Cloud Run functions differ in how they build that sandbox, not in the shape of the deal.
- The meter. Invocations are counted and duration is measured, typically against the memory you asked for, so cost tracks usage instead of uptime. Every provider also caps how long one invocation may run.
- The amnesia. Local disk and in-memory variables may be gone before the next call, so anything worth keeping belongs in a database, a cache or object storage.
Those four properties explain both the enthusiasm and the complaints. Work that arrives in bursts, completes quickly and remembers nothing fits the model beautifully: webhook receivers, image and video processing, scheduled clean-up jobs, form handlers, the connective tissue between two systems that neither deserves a server of its own. Work that holds long-lived connections, benefits from a warm in-process cache, or must answer instantly after a quiet period fits badly, because an environment built on demand has to exist before it can reply. Cold starts are a genuine characteristic and not a myth, though their size depends on your runtime, your dependency bundle and the platform, so measure yours rather than trusting a blog post. The usual remedies, provisioned concurrency or a floor of always-warm instances, work by reserving capacity in advance, which quietly reintroduces the cost structure you came here to escape. That is a per-endpoint judgement, not a philosophy. It is also worth saying that none of this abolishes operational work, it relocates it: tracing a request across dozens of short-lived executions, granting each function only the permissions it needs, and living with a local development story that never quite matches production.
Cheap until it isn't
The failure mode nobody budgets for is not a big bill from real traffic, it is a small mistake multiplied by unlimited willingness to scale. A retry storm, a recursive trigger, a scheduled job that overlaps itself, a dependency that hangs until the timeout: each turns into invocations that all bill. Set a budget alarm, cap concurrency per function, give retries a dead-letter queue, and make handlers idempotent so a duplicate event is boring rather than expensive.
