Serverless doesn’t mean “no servers.” The servers are still there — we just don’t think about them. We write a function, upload it, and the cloud runs it whenever something triggers it. No provisioning, no patching, no scaling decisions. We pay per invocation, not per hour.
How It Works
We write a function that handles one event — an HTTP request, a file upload, a message from a queue. The cloud provider:
- Receives the event
- Spins up our function in a container (or reuses a warm one)
- Runs our code
- Shuts down when done
- Charges us for the milliseconds of execution
# AWS Lambda example — a simple Node.js function
# handler.js
exports.handler = async (event) => {
const name = event.queryStringParameters?.name || "World";
return {
statusCode: 200,
body: JSON.stringify({ message: `Hello, ${name}!` }),
};
};
That’s it. No Express server, no port configuration, no process manager. Just a function.
The Event-Driven Pattern
Serverless shines when events drive the workflow. Instead of a monolith doing everything, we chain small functions together.
No server running 24/7 waiting for uploads. Each piece runs only when triggered, scales independently, and costs nothing when idle.
Key Serverless Services
Compute:
- AWS Lambda / Google Cloud Functions / Azure Functions — run code on events
- Cloudflare Workers — runs at the edge (CDN nodes), ultra-low latency
API Layer:
- API Gateway (AWS, GCP) — routes HTTP requests to Lambda functions, handles auth, rate limiting, CORS
Messaging:
- SQS (Simple Queue Service) — message queue, guarantees delivery, decouples services
- SNS (Simple Notification Service) — pub/sub, fan out one event to many subscribers
- EventBridge — event bus for routing events between AWS services
# AWS SAM template — Lambda behind API Gateway
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
HelloFunction:
Type: AWS::Serverless::Function
Properties:
Handler: handler.handler
Runtime: nodejs20.x
Timeout: 10
MemorySize: 128
Events:
Api:
Type: Api
Properties:
Path: /hello
Method: get
When Serverless Makes Sense
- Sporadic workloads — a function that runs 100 times a day costs almost nothing
- Event processing — file uploads, webhooks, queue consumers
- APIs with variable traffic — scales to zero when nobody’s calling
- Cron jobs — scheduled Lambda beats keeping a server running 24/7 for a 5-minute task
When It Doesn’t
Cold starts — if a function hasn’t been invoked recently, the first invocation takes 100ms-2s to spin up. For latency-sensitive APIs, this can hurt.
Execution limits — Lambda maxes out at 15 minutes. Long-running tasks (video processing, ML training) need a different approach.
Vendor lock-in — Lambda code is easy to port, but once we’re deep into SQS + SNS + Step Functions + DynamoDB, switching providers is a massive effort.
Complex local development — replicating the Lambda + API Gateway + DynamoDB stack locally requires tools like SAM or Serverless Framework. It’s doable but more friction than running a local Express server.
High-throughput, steady traffic — if we’re running 10 million invocations per hour consistently, a container on ECS or a Kubernetes pod would be cheaper.
Cost Model
# Lambda pricing (approximate):
# $0.20 per 1 million requests
# $0.0000166667 per GB-second of compute
#
# Example: 1 million requests, each using 128MB for 200ms
# Compute: 1M × 0.128GB × 0.2s × $0.0000166667 = $0.43
# Requests: 1M × $0.0000002 = $0.20
# Total: ~$0.63 for 1 million invocations
In simple language, serverless is about writing code and letting the cloud handle everything else. It’s perfect for bursty, event-driven workloads. But for always-on, high-throughput services, running our own containers is usually cheaper and gives us more control.