StackPractices
intermediate By Mathias Paulenko

Capacity Planning Template

A reusable template for planning system capacity, estimating growth, and preventing performance bottlenecks before they happen.

Overview

Capacity planning answers a simple question: will our systems handle the load we expect over the next 12-24 months? Getting it right takes numbers, not gut feel. This template helps you collect that data, estimate growth, and plan scaling before bottlenecks hit production — and before an emergency purchase order lands on your desk. For the methodology behind the template (forecasting math, load testing, scaling strategies), see the capacity planning guide.

The template walks through the full planning loop:

  1. Current resource baseline — what you have now and how much of it is used
  2. Growth projections — traffic, data, and user growth estimates
  3. Bottleneck analysis — which component will break first
  4. Scaling plan — what to add, when, and how much it costs
  5. Review schedule — when to revisit and adjust
Capacity planning loop: collect baseline, model growth, find the first bottleneck, plan scaling actions, then review quarterly and feed actuals back into the baseline

How to Collect the Baseline

The template is only as good as the data feeding it. Pull at least 90 days of metrics before filling section 1 — a single snapshot lies about peaks.

  • Compute: kubectl top pods / aws cloudwatch get-metric-statistics per service, P95 and max, not averages.
  • Database: connection count (pg_stat_activity), storage (pg_database_size), replication lag, and the top queries by total time from pg_stat_statements.
  • Network: LB/router throughput and requests per second; note whether peaks correlate with deploys or cron jobs.
  • Cost: current monthly spend per component — you’ll need it when the scaling plan asks for budget.

Record where each number came from. When the plan is wrong later — and it will be — you want to know which assumption drifted, not stare at a stale table.

A note on projections: never present a single number. Model three ranges — low (current trend), base (product roadmap), high (launch or campaign burst) — and size for the high case on critical paths. A projection without a range is a guess wearing a spreadsheet.

Template

# Capacity Plan: [System Name]

## 1. Current Baseline (as of [date])

### Compute Resources

| Service | Instance type | Count | CPU avg | CPU peak | Memory avg | Memory peak | Notes |
|---------|--------------|-------|---------|----------|------------|-------------|-------|
| API servers | c6i.xlarge | 6 | 35% | 72% | 45% | 68% | Auto-scaling 4-10 |
| Workers | c6i.large | 4 | 20% | 55% | 30% | 50% | Batch processing |
| Dashboard | t3.medium | 2 | 15% | 40% | 25% | 45% | Static + SSR |

### Database Resources

| Cluster | Type | Storage used | Storage capacity | Connections avg | Connections peak | Replication lag |
|---------|------|-------------|-----------------|-----------------|------------------|-----------------|
| Primary | r6i.2xlarge | 340 GB | 500 GB | 80 | 140 | — |
| Replica 1 | r6i.large | 340 GB | 500 GB | 45 | 90 | < 1s |
| Replica 2 | r6i.large | 340 GB | 500 GB | 30 | 60 | < 1s |

### Network

| Metric | Current avg | Current peak | Limit | Headroom |
|--------|-------------|--------------|-------|----------|
| Bandwidth in | 120 Mbps | 280 Mbps | 1 Gbps | 72% |
| Bandwidth out | 200 Mbps | 450 Mbps | 1 Gbps | 55% |
| Requests/sec | 8,000 | 18,000 | 25,000 | 28% |

### Storage Growth

| Dataset | Current size | Growth rate | Projected in 12 months | Retention policy |
|---------|-------------|-------------|------------------------|------------------|
| User data | 12 GB | 0.5 GB/month | 18 GB | Indefinite |
| Orders | 45 GB | 3 GB/month | 81 GB | 7 years (legal) |
| Audit logs | 120 GB | 8 GB/month | 216 GB | 90 days hot, 1 year cold |
| Media uploads | 800 GB | 40 GB/month | 1,280 GB | Indefinite |

## 2. Growth Projections

### Traffic Projections

| Metric | Current (monthly) | Q+1 | Q+2 | Q+3 | Q+4 | Source |
|--------|-------------------|-----|-----|-----|-----|--------|
| Active users | 50,000 | 58,000 | 67,000 | 78,000 | 90,000 | Product roadmap |
| API requests | 24M | 28M | 33M | 38M | 44M | 15% MoM growth |
| Peak RPS | 18,000 | 21,000 | 24,000 | 28,000 | 32,000 | Load tests |
| Storage added | 51 GB | 52 GB | 53 GB | 54 GB | 55 GB | Linear trend |

### Assumptions

- User growth: 15% month-over-month (based on last 6 months)
- API requests per user: stable at ~480/month
- Peak traffic: 2.5x average (based on load test data)
- Marketing campaigns: Q3 product launch may cause 3x burst for 2 weeks
- No major architecture changes are planned — if one lands mid-quarter, the projection resets

### Risk factors

- **Q3 product launch** — marketing expects 3x traffic burst for 2 weeks. Plan for 50k RPS peak.
- **Holiday season** — historical 2x traffic in November-December.
- **New enterprise customer** — sales pipeline includes a 10k-user enterprise contract (Q2). Would add 20% to user base overnight.

## 3. Bottleneck Analysis

| Component | Current limit | Projected breaking point | When | Mitigation |
|-----------|--------------|-------------------------|------|------------|
| API servers (CPU) | 25k RPS | ~28k RPS at current efficiency | Q3 | Add 2 instances + optimize hot paths |
| Database connections | 200 max | ~180 at projected peak | Q2 | Add read replica + connection pooling |
| Primary DB storage | 500 GB | ~480 GB in 12 months | Q4 | Provision 1 TB or partition old data |
| Bandwidth out | 1 Gbps | ~800 Mbps at projected peak | Q3 | Upgrade to 2 Gbps or add CDN |
| Audit log storage | 500 GB allocated | ~480 GB in 12 months | Q4 | Move to cold storage (S3 Glacier) |

## 4. Scaling Plan

### Q1 (current quarter)

| Action | Component | Cost (monthly) | Justification |
|--------|-----------|---------------|---------------|
| Add 2 API instances | API servers | $480 | Headroom for Q2 growth |
| Enable connection pooling | Database | $0 (config change) | Prevent connection exhaustion |
| Set up CDN for media | Network | $200 | Reduce bandwidth pressure |

### Q2

| Action | Component | Cost (monthly) | Justification |
|--------|-----------|---------------|---------------|
| Add read replica 3 | Database | $320 | Enterprise customer read traffic |
| Upgrade bandwidth to 2 Gbps | Network | $150 | Q3 launch burst preparation |
| Implement audit log archival | Storage | $50 (Glacier) | Prevent storage exhaustion |

### Q3

| Action | Component | Cost (monthly) | Justification |
|--------|-----------|---------------|---------------|
| Add 4 API instances (burst pool) | API servers | $960 | Product launch 3x traffic |
| Add 2 worker instances | Workers | $240 | Batch processing for new users |
| Provision 1 TB DB storage | Database | $200 | Storage growth + partitioning |

### Q4

| Action | Component | Cost (monthly) | Justification |
|--------|-----------|---------------|---------------|
| Evaluate DB partitioning | Database | Eng time | Orders table growing fast |
| Add CDN edge in APAC | Network | $300 | User growth in Asia region |

### Total projected cost increase

| Quarter | Additional monthly cost |
|---------|----------------------|
| Q1 | $680 |
| Q2 | $520 |
| Q3 | $1,400 |
| Q4 | $300 |
| **Total annual increase** | **$2,900/month average** |

## 5. Review Schedule

| Review | Date | Owner | Focus |
|--------|------|-------|-------|
| Q1 review | 2026-04-01 | Platform team | Validate Q1 actions, adjust Q2 plan |
| Q2 review | 2026-07-01 | Platform team | Post-launch capacity check |
| Q3 review | 2026-10-01 | Platform team | Holiday prep, Q4 adjustments |
| Q4 review | 2027-01-01 | Platform team | Annual recap, next-year plan |

From Plan to Budget

A capacity plan that nobody funds is a spreadsheet. The cost table in section 4 exists because scaling decisions compete with every other engineering budget line — present them in the same language. Sum the monthly delta per quarter, show what breaks if the spend is deferred, and give finance the lead time they ask for (usually a full quarter for committed-use discounts).

The trade-off worth spelling out: over-provisioning critical paths buys reliability per dollar; auto-scaling bursty paths buys efficiency per dollar. A plan that picks one strategy for everything is either wasteful or fragile. Critical path first, elastic second — and say which is which in the plan so the reviewer doesn’t have to guess.

What Works

  • Plan before the bottleneck — Capacity planning is proactive, not reactive. If you’re already at 80% utilization, you’re late
  • Use load testing data — Don’t guess; run load tests to find real breaking points
  • Include a safety margin — Aim for headroom of at least 30-40% above projected peak load
  • Review quarterly — Growth assumptions change; revisit capacity plans every quarter, and always after a launch, a big customer onboarding, or a burst event that broke a projection
  • Document dependencies — A database replica limit affects application capacity even if app servers have spare CPU. See the System Diagram Template for dependency mapping.
  • Model burst traffic — Plan for 2-3x normal peak during marketing campaigns or viral events. If the burst doubles your bill for two weeks, that’s still cheaper than holding that capacity idle the other 50 weeks.
  • Account for data retention — Storage grows continuously even if user growth is flat
  • Include cost projections — Capacity decisions have budget impact; finance needs lead time, and a plan without a cost column is a wish list
  • Track actuals vs projections — Compare predicted growth to actual every quarter. Adjust your model. A plan that’s consistently off by more than 20% has a modeling problem, not a capacity problem — find which assumption (per-user requests, burst multiplier, storage-per-user) is drifting and fix the input, not the symptom.

Common Mistakes

  • Using average load instead of peak load for planning — averages hide the moments that cause outages
  • Ignoring non-linear scaling — Some components degrade faster after a threshold (e.g., database lock contention)
  • Not involving finance early — Surprise budget approvals kill timelines
  • Forgetting about non-production environments — Staging and CI also need capacity
  • Planning only for compute, ignoring storage — Disk capacity exhausts silently and kills services
  • Assuming linear growth indefinitely — growth rates change; revisit assumptions quarterly
  • Ignoring connection limits — databases and load balancers have hard connection limits that hit before CPU or memory
  • Not planning for rollback — if you scale up and then traffic drops, can you scale back down?

Detailed Scenario: Product Launch Capacity Preparation

System: E-commerce platform
Event: New product launch (Q3)
Expected traffic: 3x normal peak for 2 weeks

Step 1 - Collect baseline data:
  $ kubectl top pods -n production --sort-by=cpu
  $ aws cloudwatch get-metric-statistics \
      --namespace AWS/RDS \
      --metric-name DatabaseConnections \
      --start-time 2026-06-01 --end-time 2026-06-30 \
      --period 3600 --statistics Average,Maximum

  Results:
  - API servers: 6 instances, CPU peak 72%, memory peak 68%
  - DB connections: peak 140 of 200 max (70% utilization)
  - RPS peak: 18,000 of 25,000 limit (28% headroom)

Step 2 - Project launch load:
  - Expected peak RPS: 18,000 * 3 = 54,000
  - Expected DB connections: 140 * 3 = 420 (exceeds 200 max)
  - Expected API CPU: 72% * 3 = 216% (exceeds 100% per instance)

Step 3 - Identify bottlenecks:
  1. DB connections: exhausted at 200 (critical)
  2. API CPU: need 3x instances or optimization
  3. Bandwidth: 450 Mbps * 3 = 1,350 Mbps (exceeds 1 Gbps)

Step 4 - Mitigation plan:
  - DB: add 2 read replicas + connection pooling (pgbouncer)
    Config: pool_mode=transaction, max_client_conn=500
  - API: add 12 instances to burst pool (total 18)
    Auto-scaling: min=6, max=20, target CPU=60%
  - Network: upgrade to 2 Gbps + enable CDN for static assets
  - Pre-warm: scale to 18 instances 1 hour before launch

Step 5 - Load testing:
  $ k6 run --vus 500 --duration 10m launch_test.js
  $ locust -f locustfile.py --host https://staging.example.com \
      --users 1000 --spawn-rate 50

  Acceptance criteria:
  - P99 latency < 500ms at 50k RPS
  - Error rate < 0.1%
  - DB connections < 180 with pooling
  - CPU < 70% across all instances

Step 6 - Rollback plan:
  - If error rate > 1%: enable degraded mode (rate limiting)
  - If DB connections > 190: activate circuit breaker on reads
  - If CPU > 85% for 5 min: manually scale to 24 instances

How do I calculate the required safety margin?

Rule of thumb: 30-40% above projected peak. For critical systems (payments, authentication), aim for 50%. The margin covers surprises: higher-than-expected peaks, performance degradation under load, and auto-scaling reaction time. Below 20% margin, you’re one bad day from an outage.

What metrics should I track to detect bottlenecks early?

Track: CPU per service, memory per service, DB connections, P99 latency per endpoint, error rate, message queue depth, and disk utilization. Set alerts at 70% of each limit. If a metric hits 80%, you are already in the danger zone.

The less obvious ones matter more: connection pool wait time, queue backlog age (not just depth), and disk growth rate versus the retention schedule. Saturation metrics — how close each resource is to its limit — predict trouble earlier than latency does, because latency only moves once you’re already saturated.

Variants

Cloud-native (auto-scaling)

With auto-scaling, the planning work moves to thresholds and limits instead of pre-provisioning hardware. Track: min/max instance counts, scaling cooldown periods, and instance warm-up time. The risk is scaling lag — auto-scaling reacts after load increases, so you still need headroom.

On-premise (fixed capacity)

On-premise requires longer lead times for hardware procurement (4-8 weeks). Plan 6 months ahead. Maintain a hardware inventory with age and expected replacement dates. Capacity decisions are harder to reverse — which is why the over-provision margin on-premise runs higher than cloud (40-50% vs 30-40%) and why hardware refreshes belong inside the capacity plan, not in a separate spreadsheet.

Hybrid

Critical paths on-premise for compliance or latency, elastic workloads on cloud. The hard part is visibility: you need one place where both sides’ utilization shows up together, otherwise each half gets planned in isolation and the bottleneck lands on the link between them.

Serverless (pay-per-use)

Serverless reduces capacity planning for compute but introduces new constraints: cold start latency, concurrent execution limits, and per-function timeouts. Plan for peak concurrency (which can hit the account-level quota, not the function), memory allocation per invocation, and total cost at projected volume — serverless scales gracefully but bills linearly, so the “capacity” question becomes a cost-forecasting question more than a sizing one.

Troubleshooting

  • Projections keep coming in low: single-point estimates almost always undershoot. Model three ranges (low/base/high) and plan against the high one — the difference is usually the marketing burst you didn’t price in.
  • Auto-scaling never catches the spike: scaling lag is real — instances take minutes to boot and warm up while traffic arrives in seconds. Keep the minimum high enough for the fast ramp and pre-warm before planned events.
  • A hidden limit hits before CPU: connection pools, file descriptors, and load balancer limits exhaust before compute does. List every hard limit per component in the bottleneck table, not just CPU/memory.
  • Storage fills faster than forecasted: data grows even when traffic is flat — retention policies, audit logs, and feature releases all add storage per user. Check the real growth rate monthly, not at annual review.
  • Staging collapses under the load test: if staging has half the capacity of production, your breaking-point numbers are fiction. Match the critical path sizing or annotate which numbers are extrapolated.

Frequently Asked Questions

How far ahead should I plan?

For stable systems, 12 months is sufficient. For high-growth products or before major launches, plan 18-24 months ahead with quarterly checkpoints.

Should I over-provision or scale on demand?

Over-provision critical paths (authentication, payment processing) and use auto-scaling for bursty, non-critical workloads. Cost vs. reliability trade-off depends on your SLA.

What if growth projections are wrong?

Build flexibility into your architecture (containerized workloads, infrastructure as code) so you can pivot between vertical and horizontal scaling without rewriting the application.

How do I estimate storage growth?

Look at historical data. If you have 6+ months of storage metrics, calculate the monthly growth rate and project forward. Account for new features that may add storage-per-user (e.g., file uploads, audit logging). When the estimate is shaky, pad it 20%.

Should I include disaster recovery capacity?

Yes. DR capacity belongs in the same plan — it's not a separate exercise. If your DR site needs to handle 100% of production load, it needs the same capacity. If it only handles 50% (degraded mode), document that explicitly.

How do I handle sudden traffic spikes (viral events)?

Set up auto-scaling with aggressive upper bounds, use a CDN for static content, and implement rate limiting to protect backend services. Pre-warm instances before planned events. For unplanned spikes, have a runbook that describes how to manually add capacity and enable degraded modes. See Circuit Breaker Pattern for degradation strategies.

What tools should I use for capacity planning?

Use your monitoring system (Prometheus, Datadog, CloudWatch) for historical data. Use load testing tools (k6, Locust, JMeter) for breaking-point data. Use spreadsheets or dedicated capacity planning tools (Kubecost for Kubernetes, AWS Compute Optimizer) for projections. The tool matters less than the discipline of reviewing regularly.