Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Capacity Planning for Production Systems

By Kokil Thapa | Last reviewed: September 2026

Capacity planning for production systems is the work of matching server, database, and queue resources to real traffic before users feel the pain. A booking portal that handles 200 concurrent users fine in March can collapse during Dashain unless you forecast load, measure headroom, and rehearse failure modes. This guide walks through the same workflow I use on capacity planning for growing systems and on live Laravel stacks maintained with Linux system administration practices.

What is capacity planning for production systems?

Capacity planning answers one question with numbers: can this stack handle expected peak load with acceptable latency and error rates? You are not guessing VPS sizes from a pricing page. You are tying business events—campaign launches, tax deadlines, festival booking windows—to CPU, memory, database connections, and queue depth.

On production Laravel applications I maintain, capacity planning sits beside deployment and backup work. It is part of support and maintenance, not a one-time architecture slide. The output is a living document: baseline metrics, peak targets, scaling actions, and owners.

Production Capacity StackUsers / TrafficLoad BalancerSSL, health checksApp Tier (PHP-FPM / Laravel)Workers, opcache, sessionsMySQL / PostgreSQLConnections, IOPSRedis 8.10Cache, queues, sessionsObject StorageMedia, exports
Capacity planning for production systems starts by mapping every tier that can saturate under peak load.

Think in three layers: compute (web and workers), data (database and cache), and egress (API calls, email, payment gateways). Each layer has a different bottleneck signature. CPU spikes often trace to PHP-FPM saturation or missing query indexes. Memory pressure shows up in Redis eviction or MySQL buffer pool churn. Latency jumps may be external—payment callbacks, SMS gateways—not your VPS at all.

A practical capacity plan names the constraint for each critical user journey. Checkout, document upload, and admin reporting rarely share the same limit. Split them early. That discipline matters on platforms like Adventure Third Pole Trek, where booking peaks cluster around trekking seasons rather than spreading evenly through the year.

How do you measure current capacity before you scale?

You cannot plan forward without a baseline. Collect at least four weeks of production metrics during normal and busy periods. Skip averages alone—they hide spikes that trigger outages.

Metrics that actually matter

Track these on every production stack you own:

  • Request rate and latency percentiles — p50, p95, and p99 for key routes, not global averages.
  • PHP-FPM pool utilisation — active workers, queue depth, slow requests.
  • Database — connections in use, slow query log, buffer hit ratio, replication lag if applicable.
  • Redis — memory use, evicted keys, connected clients, command latency.
  • Queue workers — jobs pending, failed jobs, processing time per job type.
  • Disk and I/O — especially on single-server setups common in budget-conscious Nepal deployments.

Export metrics to a dashboard your team checks weekly. Structured logs help post-incident review; a JSON formatter is useful when you paste log samples into tickets during triage. For Laravel apps, pair application logs with server metrics—see debugging Laravel in production safely for patterns that avoid drowning in noise.

Measure Before You ScaleCollectMetrics + logsAggregateDashboardsAlertSLO thresholdsReviewWeekly cadenceHeadroom Formula (per tier)Peak observed load × growth factor × safety marginExample: 400 req/min × 1.5 growth × 1.3 headroomTarget capacity ≈ 780 req/min sustained
Baseline metrics feed dashboards and alerts; headroom math turns observations into scaling targets.

Sample commands for a Linux + PHP-FPM host

On Ubuntu servers I administer, these read-only checks take minutes and catch obvious saturation:

# PHP-FPM status (pool name varies)
curl -s http://127.0.0.1/status?full

# Current connections and slow queries (MySQL 9.7 / 8.4)
mysql -e "SHOW GLOBAL STATUS LIKE 'Threads_connected';"
mysql -e "SHOW GLOBAL STATUS LIKE 'Slow_queries';"

# Redis memory snapshot
redis-cli INFO memory | egrep 'used_memory_human|evicted_keys'

# Disk pressure
df -h
iostat -x 1 3

Document outputs in your capacity workbook. Compare the same window after each deploy or major feature release. A Laravel production deployment checklist should include a post-deploy metrics snapshot—not just a smoke test.

How do you forecast traffic and resource needs for a web application?

Forecasting blends business input with technical modelling. Ask stakeholders for expected concurrent users, orders per hour, or API calls per minute during the next peak event. Then translate those into resource estimates using measured per-request cost from your baseline.

Build a simple forecast model

  1. List peak events for the next 12 months—festivals, sales, registration deadlines, marketing pushes.
  2. Estimate peak concurrent users or transactions per hour for each event.
  3. Multiply by measured resource cost per transaction from baseline week data.
  4. Add headroom: 30–50% for unknowns on small teams without 24/7 ops.
  5. Price infrastructure options and lead times—some hosts need 24–72 hours to resize.

For database choice, capacity characteristics differ. Read-heavy catalog sites behave differently from write-heavy booking ledgers. Compare engine trade-offs in PostgreSQL vs MySQL for production before you commit to vertical scaling alone.

Scaling approachBest whenCapacity trade-offOps complexity
Vertical scale (bigger VPS)Single-server Laravel 12/13 app, moderate trafficCeiling at host max; brief downtime on resizeLow
Horizontal app serversCPU-bound PHP-FPM, stateless sessions in RedisLinear gain until DB becomes bottleneckMedium
Read replicasReport dashboards, search-heavy pagesReplication lag affects fresh readsMedium
Queue offloadEmail, PDFs, imports, webhooksAsync delay; worker pool needs sizingMedium
CDN + edge cacheStatic assets, public catalog pagesDoes not fix dynamic checkout loadLow–medium

Queue sizing deserves explicit planning. Background jobs that worked at 500 orders/day can backlog at 5,000/day if worker count stays at two. Follow a dedicated Laravel queues with Redis production setup and size workers from peak job arrival rate, not idle averages.

Scaling Decision TreeBottleneck identified?CPU / PHP-FPMDatabase I/OScale app tierMore workers / nodesFix queries firstIndexes, cache, replicasSessions in RedisRequired for horizontalLoad test againValidate p95 latencyDocument trigger thresholds in runbook
Match scaling actions to the actual bottleneck—adding app servers rarely fixes an unindexed reporting query.

External references help when you align internal SLOs with industry framing. Google’s Service Level Objectives chapter explains error budgets in plain terms. AWS publishes reliability pillars in the Well-Architected Reliability Pillar—useful even on non-AWS VPS hosting. Laravel’s official queue documentation covers worker sizing concepts for Laravel 13.x.

What are the most common capacity planning mistakes in Laravel and PHP deployments?

Most outages I troubleshoot are predictable. The team scaled the wrong layer, skipped load tests, or treated staging as a toy environment.

Mistake 1: Scaling CPU before fixing the database

Adding a second app server doubles PHP capacity but not MySQL connection capacity. Default pools exhaust quickly when N+1 queries multiply per request. Fix query plans and indexes first. Then scale out.

Mistake 2: Ignoring opcache and deploy mechanics

PHP 8.3+ and 8.5 deployments that never reload PHP-FPM after symlink swaps serve stale bytecode under load. That looks like random latency. Tune opcache using guidance from PHP opcache configuration for production and reload FPM on every zero-downtime deploy.

Mistake 3: Staging that does not mirror production

A staging box with 1 GB RAM and SQLite tells you nothing about production MySQL behaviour. Mirror CPU class, PHP version, and data volume order-of-magnitude. See staging environments that mirror production for a practical checklist.

Mistake 4: No load test on checkout and auth

Load testing only the homepage is theatre. Script authenticated flows: login, search, add to cart, payment callback simulation, file upload. Use testing and optimization time budget for this before major campaigns—not the night before launch.

WooCommerce and Magento shops face the same patterns under different stacks. On Petals Qatar-scale international florists, payment and shipping API latency often dominates—plan external dependency timeouts and circuit breakers, not just web tier CPU.

Load Test WorkflowDefine scriptsCritical user pathsRamp traffic10 → 100 → peakWatch p95Errors, queue depthPass?Fail criteria (stop and fix)p95 latency > 2× baseline under target RPSError rate > 0.5% on checkout or authDB connections > 80% of max_connectionsRedis evictions during steady-state load
Load tests should ramp gradually and fail on explicit SLO breaches—not vague “felt slow” impressions.

How should you build a capacity plan for seasonal traffic spikes?

Seasonal spikes punish teams that plan for average traffic. Legal-tech portals, trekking bookings, and eCommerce florists all show this pattern in my client work. Build a calendar-driven plan, not a static server invoice.

90-day pre-spike checklist

  1. Confirm peak date range with the business owner—include Nepali festival windows if relevant.
  2. Re-run baseline metrics; update growth factor from last year if data exists.
  3. Schedule load test six weeks before peak; leave time for code fixes.
  4. Pre-scale infrastructure 7–14 days early; avoid emergency resize during the spike.
  5. Freeze non-critical releases two weeks before peak; deploy only fixes.
  6. Prepare rollback and comms runbook—who pauses ads if checkout degrades?

Enterprise applications with multi-tenant peaks benefit from early architecture review via enterprise application development planning—not a fire drill in production. Align with reliability practices discussed in AWS Well-Architected for reliable systems even when you run on a single EC2 or local VPS.

Cost matters for Nepal SMBs. A month of oversized hosting might run Rs 15,000–25,000 (~USD 110–185) above baseline. That is cheaper than one day of lost orders and reputation damage. Right-size after the spike—automation scripts or calendar reminders prevent paying peak prices all year.

Seasonal Spike TimelineT-90 daysT-42 load testT-14 pre-scalePeak weekForecastUpdate modelLoad testFix bottlenecksPre-scaleInfra + workersPeak opsMonitor SLOsRelease freeze windowCritical fixes only before peak
Seasonal capacity planning for production systems works best on a calendar with load tests and pre-scale lead time baked in.

After the spike, run a short retrospective. Capture actual peak RPS, max DB connections, and queue depth. Feed those into next year’s model. Speed work—caching, asset optimisation—still helps; pair capacity with speed optimization so you buy headroom with efficiency first, dollars second.

Scheduled tasks can surprise you under load. A cron that runs heavy aggregation at noon competes with checkout traffic. Shift jobs to off-peak windows using patterns from Laravel scheduled tasks in production.

Key Takeaways

  • Measure p95 latency, PHP-FPM pool use, DB connections, and queue depth for four-plus weeks before you forecast.
  • Forecast with peak load × growth factor × 30–50% headroom—not monthly averages.
  • Scale the bottleneck tier: queries and indexes before app servers; sessions in Redis before horizontal PHP.
  • Load-test authenticated checkout and upload flows; homepage-only tests miss real failure modes.
  • Pre-scale seasonal peaks 7–14 days early and freeze non-critical releases two weeks out.
  • Document scaling triggers and rollback steps in a runbook your team can execute at 2 a.m.

People Also Ask

How much headroom should a production system keep?

Most small teams target 30–50% unused capacity at expected peak. That buffer covers measurement error, sudden traffic bursts, and deploy overlap. Tighter margins need auto-scaling or on-call staff who can resize infrastructure within minutes.

When should you load test versus monitor production?

Monitor continuously in production for drift and regressions. Load test before major releases, infrastructure changes, and known peak events. Production traffic alone is a poor experiment—it risks real users when you discover limits.

Does vertical scaling ever beat horizontal scaling for PHP apps?

Yes, for single-server Laravel or WordPress stacks with moderate traffic and file-based sessions. Vertical scaling is simpler and cheaper until CPU or RAM hits the host ceiling. Past that point, horizontal app servers with Redis sessions and a tuned database tier usually win.

What metrics trigger an emergency scale-up?

Common triggers: p95 latency doubling for 10+ minutes, error rate above 0.5% on critical routes, PHP-FPM queue sustained at max children, database connections above 80% of max_connections, or Redis evictions under normal load. Define numeric thresholds in advance—not during an incident.

Turn capacity planning into a production habit

Capacity planning for production systems is not a spreadsheet you file once. It is a recurring loop: measure, forecast, test, scale, review. Teams that treat it as part of shipping—alongside deploy checklists and backups—avoid the expensive pattern of learning limits from customer complaints.

If you are preparing for growth, a seasonal launch, or a migration off undersized hosting, start with a baseline audit and a load-test window before the busy period hits. For hands-on help sizing Laravel, WooCommerce, or legal-tech portals on Nepal or global infrastructure, see the portfolio for shipped examples or planning and research services. When you are ready to stress-test your stack with someone who deploys these systems weekly, contact us to map your next peak before it maps itself onto your users.

Frequently Asked Questions

Capacity planning means measuring current throughput, forecasting peak demand with headroom, load-testing critical paths, and defining scaling triggers before traffic forces emergency upgrades.

Most small teams target 30–50% unused capacity at expected peak. That buffer covers measurement error, sudden bursts, and deploy overlap.

Monitor continuously for drift and regressions. Load test before major releases, infrastructure changes, and known peak events—not during live traffic.

Collect at least four weeks of production metrics during normal and busy periods—skip averages alone because they hide spike-triggering peaks. Track request rate with p50, p95, and p99 latency on key routes; PHP-FPM active workers, queue depth, and slow requests; database connections, slow query log, buffer hit ratio, and replication lag; Redis memory, evicted keys, and command latency; queue pending and failed jobs; plus disk and I/O on single-server setups. Export to a dashboard checked weekly, document outputs in a capacity workbook, and compare the same window after each deploy or major release.

Request rate and latency percentiles on critical routes—not global averages—tell you whether users feel pain. PHP-FPM pool utilisation shows compute saturation before errors spike. Database connections and slow queries expose index and query-plan problems. Redis evictions signal cache pressure. Queue depth and processing time per job type reveal background bottlenecks. Disk and I/O matter on budget single-server deployments common in Nepal. Pair application logs with server metrics on Laravel stacks so triage stays actionable rather than noisy.

Define numeric thresholds before an incident, not during one. Common triggers include p95 latency doubling for ten or more minutes, error rates above 0.5% on critical routes, PHP-FPM queue sustained at max children, database connections above 80% of max_connections, or Redis evictions under normal load. Document these in a runbook with owners and rollback steps so on-call staff can act at 2 a.m. without debating what “slow” means.

Forecasting blends business input with technical modelling. List peak events for the next twelve months—festivals, sales, registration deadlines, marketing pushes—and ask stakeholders for expected concurrent users or transactions per hour. Multiply by measured resource cost per transaction from baseline data, then add 30–50% headroom for unknowns on small teams without 24/7 ops. Price infrastructure options and lead times because some hosts need twenty-four to seventy-two hours to resize. Match scaling actions to the actual bottleneck tier rather than defaulting to a bigger VPS.

Yes, for single-server Laravel 12/13 or WordPress stacks with moderate traffic and file-based sessions. Vertical scaling is simpler and cheaper until CPU or RAM hits the host ceiling, often with brief downtime on resize. Past that point, horizontal app servers with Redis-backed sessions and a tuned database tier usually win. Read replicas help report dashboards and search-heavy pages but introduce replication lag on fresh reads. Queue offload handles email, PDFs, imports, and webhooks asynchronously but requires explicit worker sizing from peak job arrival rate.

Scaling CPU before fixing the database doubles PHP capacity but not MySQL connection capacity when N+1 queries multiply per request—fix indexes and query plans first. Ignoring opcache and deploy mechanics on PHP 8.3+ and 8.5 causes stale bytecode and random latency unless PHP-FPM reloads after every zero-downtime symlink swap. Staging with 1 GB RAM and SQLite tells you nothing about production MySQL behaviour—mirror CPU class, PHP version, and data volume order-of-magnitude. Load testing only the homepage misses checkout, auth, upload, and payment callback failure modes.

Build a calendar-driven plan, not a static server invoice. Ninety days before peak, confirm date ranges with the business owner—including Nepali festival windows where relevant—and re-run baseline metrics with last year’s growth factor. Schedule a load test six weeks before peak to leave time for code fixes. Pre-scale infrastructure seven to fourteen days early, freeze non-critical releases two weeks out, and prepare a rollback and comms runbook. After the spike, capture actual peak RPS, max database connections, and queue depth for next year’s model, then right-size hosting so you are not paying peak prices all year.

Think in compute, data, and egress. Compute covers web servers and queue workers—CPU spikes often trace to PHP-FPM saturation or missing query indexes. Data covers the database and cache—memory pressure shows up in Redis eviction or MySQL buffer pool churn. Egress covers external API calls, email, SMS, and payment gateways where latency jumps may not be your VPS at all. A practical plan names the constraint for each critical user journey because checkout, document upload, and admin reporting rarely share the same limit.

Adding a second app server doubles PHP-FPM capacity but not MySQL connection capacity. Default connection pools exhaust quickly when N+1 queries multiply per request, so latency climbs even though CPU graphs look healthy. On production Laravel applications, fix query plans and indexes first, then scale out. Horizontal app servers with stateless sessions in Redis help only after the database tier is tuned. Read replicas address report and search-heavy read load but add replication lag that affects fresh reads if you scale that tier without understanding query patterns.

Size workers from peak job arrival rate, not idle averages. Background jobs that handled five hundred orders per day fine can backlog at five thousand per day if worker count stays at two. Track jobs pending, failed jobs, and processing time per job type alongside web-tier metrics. Queue offload moves email, PDF generation, imports, and webhooks off the request path but introduces async delay—the worker pool becomes its own capacity tier with its own saturation signature. Plan explicit worker counts before campaigns, not the night before launch.

For Nepal SMBs, a month of intentionally oversized hosting during a peak window might run Rs 15,000–25,000 (~USD 110–185) above baseline. That is typically cheaper than one day of lost orders, failed checkouts, and reputation damage during a festival or booking surge. Pre-scale seven to fourteen days early rather than emergency-resizing mid-spike when hosts may need twenty-four to seventy-two hours to provision. After the event, right-size with calendar reminders or automation scripts so peak pricing does not run all year.

On Ubuntu servers, read-only checks take minutes and catch obvious saturation. Curl PHP-FPM status at the local pool endpoint for active and queued workers. Query MySQL 9.7 or 8.4 for Threads_connected and Slow_queries. Run redis-cli INFO memory for used_memory_human and evicted_keys. Check disk pressure with df -h and iostat -x 1 3. Document outputs in your capacity workbook alongside p95 latency and queue depth from application dashboards. Compare the same measurement window after each deploy—a Laravel production checklist should include a post-deploy metrics snapshot, not just a smoke test.

Share this article

0 Comments

Leave a comment

Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

Quick Contact Options
Choose how you want to connect me: