The Runtime Theory
Cloud & InfrastructureUpdated

Serverless Is Still a Server

There is no code without a machine, a kernel, and a cold start. What serverless actually automates, and where the abstraction leaks.

The Runtime Theory Team3 min read#serverless#functions#virtualization#cloud
On this page

Somewhere, right now, your serverless function is running on a server. It has a kernel. It has an IP address. It can produce stack traces with real frame addresses and interact with real filesystems. The marketing name is a product decision — but the runtime is still machinery, and the machinery decides your latency, your limits, and your failure modes.

What serverless actually automates

"Serverless" = a runtime provider (AWS Lambda, Cloudflare Workers, Vercel Functions) automating three historically painful jobs:

text
provisioning  —  you never request an instance; it exists when your function is invoked
lifecycle     —  scale-out is free (limited only by concurrency budgets and cold starts)
scheduling    —  the cloud decides which machine runs your function, and when to freeze it

The automation is real, and it eliminates an entire class of operational failure (leaked instances, misconfigured autoscaling, version skew across a frozen fleet). What it does not automate is the physics: the machine's memory, its cold start, its network namespace, its time sliced with other tenants.

The cold start is the whole physics lesson

A cold start is the interval between "invoke" and "your handler's first line", and it is composed of verifiable steps:

text
1. scheduler picks a worker (a machine with spare capacity)      ~10–100 ms
2. sandbox creation (container/vm/isolate, network namespace)    ~50–300 ms
3. runtime bootstrap (node/python process init, imports)         ~10–200 ms
4. your handler's first instruction                              ★ warm: ~1–5 ms

The platform's answer to "cold start is slow" is warmth as a cache: keep an idle instance alive a few minutes. The consequence is what everyone eventually hits — concurrency is cold start times burst: a spike of N requests hits N cold starts in parallel, and the request that "should cost 2 ms" costs the cold start of its container. The documented limit (1,000 concurrent executions, or whatever the platform configures) is not a quota — it is the cold start budget over time.

What the abstraction genuinely hides

A function's per-invocation behavior is deterministic and testable. The platform-dependent parts are not, and they're the ones that break:

  • Ephemeral state. Local disk, in-memory caches, open sockets — all of it can vanish between invocations, including while your function runs (scale-down kills instances). This is why "I cached this in a module variable" is a race with the collector.
  • Limits real resources. Directory entries, file descriptors, open sockets, memory — sandboxes enforce fixed ceilings on all of them. Your code can't see them until it violates them; the error then surfaces as a generic platform exception.
  • Time and size ceilings. Execution time, response size, upload size — enforced by the platform's scheduler, not your code. "Just increase the timeout" is a recurring cost, not a fix.
  • The network position. Every function has an IP; it uses real (NATed) networking, with real DNS timeouts and real connection limits. The AWS Lambda ↔ VPC networking saga — where a per-invocation ENI warm pool existed and cold ENI attach added seconds — is a museum exhibit of "virtualization is real".

When the abstraction helps, and when it bites

Helps: bursty, heterogeneous, event-driven work — webhook handlers, image resize, a churning aggregation job, a streaming queue consumer. The platform's free scale-out wins where a fleet would idle.

Bites: latency-critical, stateful, steady-state workloads. A serverless function is always at least one hop through the provider's infrastructure; the warm path is a lightweight "real" service, the cold path is a timeout generator. Yours is a YouTube-upload processing pipeline or a primary user-facing API — and someone measured.

The decision rule is the same as for every abstraction: the abstraction is worth it when the difference between the abstraction and the machine doesn't show up in your SLO. Hot path latency, sustained concurrency, and stateful protocols are precisely where it does.

The runtime view of "serverless"

  • Provisioning answers: p99 including cold starts, not the warm median.
  • Concurrency budgets are cold-start budgets; the answer to "just parallelize" is "parallel cold starts".
  • Ephemeral everything: make your writes transactional, your caches external, your sockets short-lived.
  • It's still a server, and someone's still paying rent on it — in latency or in dollars.