Why Serverless? #
The question “why serverless?” doesn’t just come from junior engineers. Senior engineers, tech leads, even CTOs often ask it — and it’s a valid question. Serverless is not just a trend; it’s the logical consequence of how we’ve evolved building, running, and scaling systems.
Serverless doesn’t mean there are no servers. The servers still exist on the provider’s side. What changes is who is responsible for those servers — and the answer is no longer the engineering team. This article covers the root problems behind serverless, the real advantages it offers, the pitfalls that are often overlooked, and a pragmatic guide for when serverless is the right choice.
The Fundamental Problems of Traditional Architecture #
Before discussing why serverless is attractive, we have to be honest about the problems it’s actually trying to solve. These problems aren’t hypothetical — every backend engineer has experienced them.
Infrastructure as Cognitive Load #
In traditional architecture (VM or bare metal), engineering teams spend time on things that aren’t directly related to business value:
Traditional responsibilities:
✓ Physical/virtual server provisioning
✓ OS and dependency patching
✓ Network & firewall configuration
✓ Resource monitoring (CPU, RAM, disk)
✓ Capacity planning for peaks
✓ Credential & secret rotation
✓ Backup & disaster recovery setup
All of that is legitimate — but the time spent on it is time not spent on product features, UX optimization, or business experiments.
A rarely discussed reality: in many teams, 30–50% of engineering time goes to infrastructure operations. Serverless doesn’t eliminate all of it, but it shifts most of it to the provider — and that alone is a game changer.
Over-Provisioning vs Under-Provisioning #
The classic capacity planning dilemma:
flowchart LR
A["Traffic forecast"] --> B{"Decision"}
B -- "Too large" --> C["Money wasted<br/>80% resources idle"]
B -- "Too small" --> D["Downtime & latency<br/>unhappy users"]
B -- "Just right (rare)" --> E["Minimal luck<br/>Ops pulled overtime"]Autoscaling in the traditional model does help, but:
- Its configuration is complex — min/max instances, cooldown, metric thresholds
- Scaling isn’t instant — VM or container spin-up takes time
- A baseline is still required — at least 1–2 instances must stay alive 24/7
The result: teams keep paying for idle resources just to handle spikes that may never come.
An Inefficient Cost Model #
On traditional VMs or containers, the bill is very unfriendly to fluctuating traffic:
| Scenario | Traffic | What You Pay | Reality |
|---|---|---|---|
| Nighttime (idle) | 0 requests | 100% capacity | Pay in full |
| Weekend (quiet) | 5% capacity | 100% capacity | Pay in full |
| Payday (peak) | 300% capacity | 100% capacity + throttling | Pay in full + user complaints |
Yet most modern applications share these characteristics:
- Event-driven — only works when there’s a trigger
- Inconsistent traffic — peaks at certain hours, quiet at others
- Sporadic — some features may be called hundreds of times a day, others only 5 times a month
For patterns like these, the pay-per-idle model is systematic waste.
Slow Time-to-Market #
Every new service in traditional architecture often triggers a long ritual:
Setting up a new service — traditional checklist:
□ Provision server/cluster
□ Set up load balancer
□ Configure auto-scaling
□ Set up CI/CD pipeline
□ Integrate monitoring & alerting
□ Set up log aggregation
□ Configure secret management
□ Test failover & recovery
□ Security review approval
□ ... only then start coding
The result:
Ideas are fast, but implementation is slow.
This is a big problem in startup environments or product teams that need to validate hypotheses in days, not months.
Serverless as the Evolutionary Answer #
Serverless didn’t appear out of nowhere. It is an advanced abstraction continuing a trend that started with virtualization:
flowchart LR
A["Physical Server"] -->|"Hardware abstraction"| B["VM"]
B -->|"OS abstraction"| C["Container"]
C -->|"Server abstraction"| D["Serverless"]
style A stroke:#ff5555,stroke-width:2px
style B stroke:#ffaa00,stroke-width:2px
style C stroke:#0080ff,stroke-width:2px
style D stroke:#00bb00,stroke-width:2pxEach step simplifies one layer that was previously the developer’s responsibility:
| Era | Developer Responsible For | What Gets Abstracted |
|---|---|---|
| Physical server | Hardware, racks, cables | — |
| VM | OS, patches, network | Hardware |
| Container | Image, dependencies, scaling config | OS |
| Serverless | Code, events, data | Server, runtime, scaling |
Notice the difference: in serverless, the three bottom layers (server, runtime, scaling) disappear from the developer’s responsibilities. What remains is code, events, and data — the three things with real business value.
Technical Advantages of Serverless #
1. Zero Infrastructure Management #
This is serverless’s main promise — and the one with the most visible impact:
# ANTI-PATTERN: The daily sysadmin checklist in the traditional era
# (not just time, but also human error risk)
daily_ops:
- check_disk_space: "df -h"
- check_memory: "free -m"
- rotate_logs: "logrotate"
- update_packages: "apt update && apt upgrade"
- review_alerts: "check 5 monitoring dashboards"
- backup_data: "pg_dump to S3"
# CORRECT: In the serverless era, all the checklist above
# is AWS/GCP/Azure's business. Engineers focus on code.
serverless_daily_ops:
- review_function_logs: "CloudWatch"
- review_error_rate: "Datadog"
- ship_feature: "git push origin main"
Providers offering this:
- AWS Lambda — the pioneer, most mature ecosystem
- Google Cloud Functions — native integration with GCP
- Azure Functions — tight coupling with .NET and the Azure ecosystem
- Cloudflare Workers — edge compute, ultra-low latency
2. Native, Instant Autoscaling #
Serverless has scaling capabilities that are very hard to replicate in traditional systems:
sequenceDiagram
participant T as Traffic
participant S as Serverless Platform
participant F1 as Function Instance 1
participant F2 as Function Instance 2
participant F3 as Function Instance N...
T->>S: 1 request
S->>F1: invoke
T->>S: 100 requests/sec
S->>F1: invoke
S->>F2: spawn new
T->>S: 10,000 requests/sec
S->>F1: invoke
S->>F2: invoke
S->>F3: spawn 98 more instances
Note over S: Scaling happens in milliseconds,<br/>no scaling policy configuration,<br/>no warm pool management.Serverless scaling characteristics:
| Aspect | Serverless | Traditional VM/Container |
|---|---|---|
| Scaling time | Milliseconds | Minutes (container cold start) |
| Granularity | Per request | Per instance (1 instance = N requests) |
| Configuration | Not needed | Scaling policy, thresholds, cooldown |
| Scale to zero | Native | Needs special setup (cost-saving) |
| Upper limit | Very high (hundreds of thousands concurrent) | Depends on cluster setup |
3. Pay-per-Execution #
This is often the main highlight — and it’s genuinely powerful:
Billing model comparison:
Serverless:
Pay only when code runs
- 1,000 requests × 200ms = 1,000 × duration
- 0 requests = $0
- No idle cost, no baseline
Traditional VM/Container:
Pay as long as the server is alive
- Server alive 24/7 = 720 hours/month
- 0 or 1 million requests = same bill
- There's a monthly minimum spend
The direct effects:
- Great for fluctuating traffic
- Great for sporadic workloads (cron jobs, webhooks, notifications)
- Great for startups that want cheap experimentation
4. Event-Driven as a First-Class Citizen #
Serverless is very natural with events — something often overlooked by teams coming from request-response architectures:
flowchart LR
subgraph Sources[Event Sources]
A1[HTTP Request]
A2[S3 Upload]
A3[SQS Message]
A4[CRON Schedule]
A5[DynamoDB Stream]
end
subgraph Lambda[Lambda Function]
L[Process Event]
end
subgraph Targets[Targets]
T1[Send Email]
T2[Write to DB]
T3[Trigger Workflow]
end
Sources --> Lambda
Lambda --> TargetsNatively supported event sources:
| Event Source | Example Trigger |
|---|---|
| HTTP | API Gateway request, ALB request |
| Storage | S3 upload, Cloud Storage change |
| Queue | SQS message, Pub/Sub publish |
| Database | DynamoDB stream, Firestore trigger |
| Schedule | CloudWatch Events, Cloud Scheduler |
| Stream | Kinesis, Kafka |
This encourages decoupled, reactive, and scalable system design — which usually takes major effort to achieve in traditional architecture.
Business Advantages of Serverless #
Cost Efficiency (When Used Correctly) #
Serverless is not always cheaper — but for the right workloads, the difference can be significant:
flowchart TD
A{"Traffic profile?"} -->|"Spiky/sporadic"| B["Serverless is usually cheaper"]
A -->|"Stable & high"| C["Traditional servers can be cheaper"]
A -->|"Very high, constant"| D["Reserved/committed instances win"]Examples of workloads that usually win with serverless:
- Background jobs — processes that run a few times per hour
- Webhook handlers — unpredictable traffic, spikes on external events
- Image processing — triggered only on upload
- Notification systems — email/push on specific events
- MVP APIs — low traffic, stays cheap
- ETL/data transformation — scheduled, not 24/7
Faster Time-to-Market #
| Activity | Traditional Architecture | Serverless |
|---|---|---|
| Provision server | Hours–days | 0 (already provided by platform) |
| Set up scaling | Hours of configuration | 0 (native) |
| Set up monitoring | Set up Prometheus/Grafana | Enable CloudWatch/X-Ray |
| Set up CI/CD | Jenkins/GitHub Actions + deploy config | Deploy function |
| Total time to first request | 1–3 days | 1–3 hours |
This is crucial for:
- Startups — validate ideas before running out of runway
- New products — time-to-market determines competitive advantage
- Feature validation — A/B tests at low cost
Scale Without Hiring Infrastructure Engineers #
One advantage that often goes unnoticed at first: serverless lets small teams handle large traffic.
Traditional scenario (5-engineer team):
1 Tech Lead
2 Backend Engineers
1 Frontend Engineer
1 DevOps/Infrastructure Engineer ← not needed in the serverless model
Serverless scenario (4-engineer team):
1 Tech Lead
3 Backend Engineers (all can handle infra via IaC)
The experience of many startups: with serverless, teams of 3–5 engineers can handle traffic that would normally need 10+ in traditional architecture. This isn’t hyperbole — it’s happening at many companies (Coca-Cola, Nordstrom, fintech startups) that migrated to serverless.
Serverless Fits Modern System Patterns #
Microservices #
Serverless and microservices are a natural pair:
flowchart TB
subgraph Monolith["Monolith"]
M["1 large codebase<br/>1 deployment<br/>1 team"]
end
subgraph Microservice["Microservices"]
S1["Service A<br/>1 function"]
S2["Service B<br/>1 function"]
S3["Service C<br/>1 function"]
end
subgraph ServerlessMicroservice["Serverless Microservices"]
L1["Function: Auth"]
L2["Function: Catalog"]
L3["Function: Order"]
L4["Function: Payment"]
L5["Function: Notification"]
end
Monolith -->|"Decompose"| Microservice
Microservice -->|"Run on"| ServerlessMicroserviceA serverless function is the most granular form of microservice — one function, one responsibility, one deployment.
Event-Driven and Async Systems #
Serverless is ideal for:
- Pub/Sub consumers — receive a message, process it, exit
- Queue workers — scale per message
- Stream processors — Kinesis, Kafka consumers
- Webhook handlers — invoked by events from external systems
Because all of these models:
- Scale automatically per event
- Have no idle workers when the queue is empty
- Cost zero when there are no events
Backend-for-Frontend (BFF) #
Serverless fits well for:
- Thin APIs — data aggregation for mobile/web
- Client-specific logic — different endpoints for iOS vs Android
- Lightweight gateways — routing, auth, transformation
BFF functions are usually small, fast, and cheap — exactly the serverless character.
Why Serverless Is NOT the Answer to Everything #
Now for the part marketing rarely talks about. Serverless has real limitations you need to understand before committing.
Cold Start #
Functions that are rarely invoked need startup time:
Cold start timeline:
flowchart TD
Request["Request arrives"]
Decision{"Platform finds a ready container?"}
Exec["Execute (~50ms)"]
Provision["Provision new container (~200ms–5s)"]
Init["Init runtime"]
ExecCode["Execute code"]
Request --> Decision
Decision -->|Yes| Exec
Decision -->|No| Provision
Provision --> Init
Init --> ExecCodeCold start becomes a problem for:
- Latency-sensitive APIs (real-time trading, gaming)
- Functions invoked infrequently (the first hour after deploy)
- Heavy runtimes (Java is slower than Node.js or Go)
# ANTI-PATTERN: Ignoring cold start for latency-critical use cases
# (e.g., real-time bidding, IoT commands)
function_timeout: 100ms # target response
actual_latency: 3500ms # average due to cold start
# → target is never met
# CORRECT: Choose serverless only for use cases tolerant of
# cold start, or mitigate with:
# - provisioned concurrency
# - lighter runtime
# - keep-warm strategy
# - edge functions (Cloudflare Workers, Lambda@Edge)
Vendor Lock-in #
flowchart LR
A[Code on AWS Lambda] -->|Migrate to GCP| B[Refactor handler signature]
B --> C[Update event trigger]
C --> D[Update IAM permissions]
D --> E[Re-test integration]
E --> F[Update monitoring]
F --> G[High migration cost]Each provider has:
- Its own event API (S3 events vs Cloud Storage events)
- Its own IAM model
- Its own runtime limits
- Its own pricing model (even if similar)
Migration isn’t impossible, but it’s not zero cost. Mitigation: use agnostic frameworks like the Serverless Framework, Terraform, or Pulumi for abstraction.
Observability Is Harder #
Distributed systems are genuinely harder to debug:
Serverless observability challenges:
✗ 50 functions = 50 different log streams
✗ A request passing through 5 functions = 5 hops to trace
✗ Async events = no automatic correlation ID
✗ Cold start metrics are hard to aggregate
✗ Vendor-specific tools (X-Ray, Stackdriver) aren't portable
Solution: invest in an APM tool from the start (Datadog, Lumigo, Epsagon, Thundra), implement distributed tracing, and use structured logging with correlation IDs.
Not Suitable for Long-Running Processes #
There are hard limits on execution duration:
| Platform | Max Execution Time |
|---|---|
| AWS Lambda | 15 minutes |
| Google Cloud Functions | 9 minutes (HTTP), unlimited (event) |
| Azure Functions | 10 minutes (default), 30 minutes (premium) |
| Cloudflare Workers | 30 seconds (CPU time) |
This means serverless is NOT suitable for:
- Long-duration video rendering
- ML model training
- Batch ETL processing large data
- Stateful long-lived connections (WebSocket on Lambda = anti-pattern)
- Processes that must idle waiting for external events
Decision Framework — Choose Serverless or Not #
Instead of guessing, use this framework to decide.
flowchart TD
A{"Workload profile?"} -->|"Event-driven"| B{"Need ultra-low<br/>latency?"}
A -->|"Long-running"| C["Use VM/Container"]
A -->|"Stateful persistent"| C
A -->|"Constant high traffic"| D{"Budget for<br/>reserved?"}
D -->|"Yes"| E["Use VM/Container<br/>with reserved"]
D -->|"No"| F["Serverless still possible<br/>but consider cost"]
B -->|"Yes"| G["Serverless with<br/>cold start mitigation"]
B -->|"No"| H["Excellent fit<br/>serverless ✓"]
style H stroke:#00bb00,stroke-width:2px
style C stroke:#ff5555,stroke-width:2px
style E stroke:#ffaa00,stroke-width:2px
style G stroke:#ffaa00,stroke-width:2px
style F stroke:#ffaa00,stroke-width:2pxUse Serverless If #
Excellent fit for:
✓ Event-driven workloads (webhook, queue, file upload)
✓ Inconsistent or sporadic traffic
✓ Focus on high speed-to-market
✓ Limited or no infrastructure team
✓ MVP or experiment APIs
✓ Small microservices with clear scope
✓ Scheduled jobs / cron replacement
Avoid Serverless If #
Not suitable for:
✗ Ultra-low latency (consistent sub-10ms)
✗ Long-running processes (video encoding, ML training)
✗ Stateful long-lived connections
✗ Need for full OS/hardware control
✗ Constant high-traffic workloads (reserved instances win)
✗ Compliance forbidding shared infrastructure
An important principle: serverless is a tool, not a religion. Choose based on workload profile, not hype. Teams that succeed with serverless are teams that understand when not to use it.
Common Anti-Patterns #
Some common traps when adopting serverless:
# ✗ Anti-Pattern 1: Thinking serverless = no cost
# In reality, for high and constant traffic, serverless
# can be more expensive than VMs/Containers.
# Calculate cost per 1 million requests, not generic assumptions.
# ✓ Solution: monitor billing with per-service tags,
# set up budget alarms, and review costs weekly.
# ✗ Anti-Pattern 2: Forcing a monolith into one function
# You lose all scaling, observability, and isolation benefits.
# ✓ Solution: split by domain or use case,
# use Step Functions/Workflows for orchestration.
# ✗ Anti-Pattern 3: Ignoring cold start until production
# Only realizing cold start is a problem when users complain.
# ✓ Solution: load test with realistic traffic patterns
# before launch, monitor P99 latency from day one.
# ✗ Anti-Pattern 4: Not investing in observability
# 50 functions without distributed tracing = debugging nightmare.
# ✓ Solution: APM tool + structured logging + correlation ID
# from the start, not after production goes down.
# ✗ Anti-Pattern 5: Choosing serverless because it's "cool"
# Without workload analysis, adopting serverless = technical debt.
# ✓ Solution: use the decision framework above
# for every new service, don't blanket adopt.
Summary #
← Previous: History of Serverless Next: When to Use? →
- Serverless is not a trend — it’s the logical consequence of infrastructure evolution: hardware → VM → container → function. Each step simplifies one layer.
- The main problems it solves: infrastructure operational burden, over/under-provisioning, an inefficient cost model for fluctuating traffic, and slow time-to-market.
- Technical advantages: zero infrastructure management, instant per-request autoscaling, pay-per-execution, and event-driven as a first-class citizen.
- Business advantages: cost efficiency for the right workloads, much faster time-to-market, and small teams handling large traffic.
- Best suited for: microservices, event-driven systems, BFF APIs, scheduled jobs, webhook handlers, and MVP/startups.
- Real limitations: cold start, vendor lock-in, harder observability, unsuitable for long-running processes, and potentially more expensive for constant high traffic.
- The main principle: serverless is a tool, not a religion. Use a decision framework, monitor costs, invest in observability, and don’t force it on unsuitable workloads.
- The right question isn’t “why serverless?”, but “is my problem worth solving with serverless?” — the answer determines everything.