Serverless functions: how they work and when to use them

Serverless lets you run code without managing servers and pay only when it runs. Learn the trade-offs before you commit.

Small functions firing on events and scaling automatically

Serverless does not mean there are no servers. It means you do not manage them. You upload code, the provider runs it when needed, scales it automatically and bills you for the time and resources actually used. The common form is FaaS (functions as a service), such as AWS Lambda, Google Cloud Functions, Azure Functions, Cloudflare Workers and Vercel or Netlify functions.

How it works

  1. You write a small function that takes an event and returns a result.
  2. You attach a trigger: an HTTP request, a file upload, a message in a queue, a database change or a schedule.
  3. When the trigger fires, the provider starts an environment, runs your function and may reuse that environment for later calls.
  4. If a thousand events arrive, it runs many copies in parallel. If none arrive, nothing runs and nothing is billed (apart from related services).
export async function handler(event) {
  const name = event.queryStringParameters?.name ?? "world";
  return { statusCode: 200, body: JSON.stringify({ message: "Hello " + name }) };
}

The exact signature differs by provider.

Strengths

  • No server management: no patching, no capacity planning.
  • Automatic scaling, including down to zero.
  • Pay per use, which is cheap for spiky or low traffic.
  • Fast to ship small pieces of backend logic.
  • Good fit for event-driven work.

Limits and trade-offs

  • Cold starts: the first request after idle time can be slower while a new environment starts. It varies by runtime, package size and provider. Edge runtimes are usually much quicker.
  • Time and memory limits: a function usually must finish within minutes at most, with capped memory. Long jobs need other tools.
  • Statelessness: each call may run in a different environment. Do not keep important data in memory or on local disk. Use a database, cache or object storage.
  • Database connections: many parallel functions can open too many connections and overwhelm a normal database. Use a connection pooler or a serverless-friendly database or HTTP-based driver.
  • Cost at scale: steady, heavy traffic can be more expensive than a few always-on servers.
  • Debugging and local testing are harder, and vendor lock-in can grow if you use many provider-specific triggers.
  • Long-lived connections such as WebSockets are awkward in plain functions.

Good use cases

  • Webhooks and small APIs.
  • Image resizing or processing after an upload.
  • Scheduled jobs (cron-like tasks).
  • Processing queue messages or stream events.
  • Glue between services and light automation.
  • Sites with highly variable traffic.

When a normal server or container is better

  • Constant high traffic where an always-on instance is cheaper.
  • Long-running tasks, background workers with heavy state, or WebSockets.
  • Very latency-sensitive paths where cold starts are unacceptable.
  • Apps needing special software or fine control of the environment.
  • Teams that want to avoid being tied to one provider's model.

A container platform that scales to zero is a middle path, with more freedom than functions.

Good practices

  • Keep functions small and focused, and the deployment package small to cut cold starts.
  • Make handlers idempotent. Events can be delivered more than once, so processing the same event twice must be safe.
  • Set sensible timeouts and memory, and a concurrency limit to protect downstream systems.
  • Use least-privilege roles for each function.
  • Keep secrets in a secrets manager or the platform's secret store, not in code.
  • Add logging, metrics and alerts. Use structured logs and trace IDs.
  • Put a dead-letter queue on async triggers so failed events are kept for inspection instead of being lost.
  • Watch the bill, since a bug or a loop that triggers itself can run up costs quickly.

Takeaway: serverless is great for event-driven, spiky and small workloads where you want no server work. Plan for cold starts, limits, statelessness and database connections, make handlers idempotent, and choose a normal server when traffic is steady and heavy.


Networking & Cloud series, Part 2 (cloud fundamentals): 5 of 5. Previous: Object storage (S3) basics: buckets, access and presigned URLs.

Keep reading