Both options mean you never touch a physical server. The difference is how much of the runtime you hand over to the cloud provider, and that choice shows up later in your bill, your logs and your 2 a.m. debugging sessions.

Serverless functions

With a service like AWS Lambda, you upload a function and the platform runs it whenever an event arrives: an HTTP request, a file upload, a message in a queue. You don’t think about machines at all. When nothing is happening, nothing is running and, for most setups, nothing is billed.

The limits are real, though. According to AWS’s documentation:

  • A single invocation can run for at most 15 minutes.
  • Memory can be set from 128 MB to 10,240 MB, and CPU power scales with it. At 1,769 MB a function gets the equivalent of one full vCPU.
  • Each region starts with a default of 1,000 concurrent executions, which can be raised on request.

The other cost is the cold start: when a function hasn’t run for a while, the first request has to wait while the platform spins up a fresh environment.

Containers

A container packages your app with everything it needs and runs the same way on a laptop, a server or a managed platform. Services such as Google Cloud Run sit in the middle ground: you bring a container, and the platform handles scaling. Cloud Run can even scale a service down to zero when there is no traffic, at the price of a slower first response when the next request arrives. Google describes two billing models: one with no charge while an instance is idle plus a per-request fee, and one that charges for an instance’s whole lifetime instead.

Containers handle the things functions struggle with: long-running processes, WebSockets, background workers and custom system libraries.

Three examples

  • Resizing photos when users upload them: serverless. It is short, triggered by an event and traffic comes in bursts.
  • A chat app holding thousands of open WebSocket connections: containers. Those connections live far longer than a function call.
  • A nightly report that takes 40 minutes to build: too long for a 15-minute Lambda invocation, so a container job, such as a Cloud Run job, fits better.

What about cost?

For low or unpredictable traffic, serverless is hard to beat, because idle time is free. As traffic grows steady and heavy, a few always-on containers often come out cheaper than millions of individual invocations. Measure your own numbers before you commit, because the crossover point depends on how long each request runs.

The usual answer: both

Many teams run their main API in containers and use functions for the edges: webhooks, scheduled tasks and file processing.

The hidden costs on each side

Serverless hides servers, but it adds its own work. Each function is a small deployment with its own permissions, logs and settings, and a busy project can end up with dozens of them. Tracing one user request as it hops through several functions and queues takes good tooling. Local testing is also harder, because the real environment only exists in the cloud.

Containers bring a different kind of upkeep. You own the base image, so you have to keep the operating system packages and language runtime patched. You also need to think about health checks, how many instances to keep warm and how to roll out new versions without dropping requests. Managed platforms take care of much of this, but not all of it.

Lock-in

A container image runs on almost any cloud, or on a single rented server, with few changes. Serverless functions tend to lean on one provider’s triggers, permissions model and event formats, so moving them elsewhere usually means rewriting the glue code. That is not a reason to avoid serverless, but it is worth knowing before you build a whole product out of one vendor’s functions.

A quick checklist

  • Does any single job run longer than a few minutes? Lean toward containers.
  • Is traffic spiky, with long quiet periods? Lean toward serverless.
  • Do you need open connections, custom system libraries or a specific runtime version? Containers.
  • Is the team small and short on operations experience? Managed options of either kind beat running your own servers.

What we think

The limits make most of these decisions for you. Check the timeout, memory and connection requirements of your workload first, and the choice is often obvious.

When it genuinely isn’t, pick the option your team can debug comfortably. A cheaper architecture nobody understands is not cheaper for long.