
September 11, 2026
13 min read
By Kokil Thapa | Last reviewed: September 2026
Your checkout works in staging, yet customers report timeouts on Friday evenings. Dashboards show green CPU graphs while revenue drops. That gap exists because most teams never take time to define meaningful SLIs and SLOs tied to user experience. An SLI measures what users actually feel. An SLO sets the minimum quality you promise internally. Together they turn vague "make it faster" goals into numbers your team can defend in a release meeting. This guide walks through choosing indicators, setting targets, and wiring them into a testing and optimization workflow that fits Laravel apps, APIs, and the small production stacks I maintain for clients in Nepal and abroad.
What is the difference between an SLI, an SLO, and an SLA?
These three acronyms get mixed up in stand-ups and contracts. Keep the definitions straight before you instrument anything.
An SLI (Service Level Indicator) is a measured signal. It answers: "How good was the service for users during this window?" Examples include the ratio of successful HTTP responses, p95 checkout latency, or the percentage of payment webhooks processed without retry.
An SLO (Service Level Objective) is an internal target for that SLI. It answers: "What level is acceptable?" You might aim for 99.9% availability over 30 rolling days. The SLO is a team commitment, not a legal document.
An SLA (Service Level Agreement) is a contractual promise to a customer, often with credits or penalties. Most small agencies and product teams never need an SLA on day one. Start with SLOs. Add an SLA only when a contract demands it.
The Google SRE book on service level objectives treats SLIs as ratios: good events divided by valid events. That framing prevents vanity metrics. A low CPU reading does not mean users are happy. A 200 response that took 12 seconds still counts as a failure for latency SLOs if you define your threshold honestly.
| Term | Who cares | Example | Typical owner |
|---|---|---|---|
| SLI | Engineering | 99.2% of checkout requests succeed in < 2s | Dev + ops |
| SLO | Product + engineering | 99.5% success over 30 days | Team lead |
| SLA | Customer + legal | 99.0% uptime or 10% credit | Account manager |
For deeper background on error budgets and burn rates, see our companion piece on site reliability engineering, SLIs, SLOs, and error budgets.
How do you choose meaningful SLIs for a web application?
Start with user journeys, not server metrics. On a booking portal I maintain, the critical path is search → select date → pay → confirmation email. Each step gets at most one primary SLI. If you measure everything, you alert on nothing useful.
Step 1: Map critical user journeys
List the flows that cause support tickets or lost revenue when they break. For an eCommerce store, that is usually browse, add to cart, checkout, and payment callback. For a legal-tech portal, it is document upload, form submission, and PDF generation.
Step 2: Pick SLI types that match the journey
Most web systems need a small set of indicator types:
- Availability — fraction of requests that return a successful status (2xx/3xx) within your validity rules.
- Latency — fraction of requests faster than a threshold (p95 or p99, not average).
- Correctness — fraction of business operations that complete without error (payment captured, email sent, row persisted).
- Freshness — for async jobs, how often data is updated within N minutes (report exports, search index).
Average latency lies. One slow outlier hidden in a mean still ruins a user's session. Use percentiles. I typically track p95 for user-facing pages and p99 for payment and webhook endpoints.
Step 3: Define "good" and "valid" events precisely
Write the ratio in plain language before you touch Prometheus or CloudWatch:
SLI = (successful checkout POST responses under 3 seconds) / (all checkout POST requests excluding client aborts)
Exclude events users control. A 404 from a mistyped URL is not an availability failure for your API. A 499 client-closed request should not penalize your SLO unless you explicitly own connection stability on mobile networks.
Projects like Adventure Third Pole Trek combine Livewire booking flows with supplier CRM jobs. That split naturally yields two SLIs: checkout latency and nightly sync freshness. One dashboard cannot cover both without blurring priorities.
How do you set realistic SLO targets for a small team?
Perfect is expensive. 99.99% availability allows about 4 minutes of downtime per month. Most two-person teams running Laravel on a single VPS cannot justify that cost. Pick a target you can afford to engineer toward.
Use historical data before you commit
Export 30–90 days of access logs or APM data. Calculate your current SLI. If checkout success is already 98.7%, promising 99.99% sets you up for permanent firefighting. A reasonable first SLO might be 99.5% with a plan to tighten after two quarters.
The JSON formatter tool helps sanity-check exported metric payloads before you pipe them into spreadsheets or Grafana transforms. Small tooling saves hours when you are prototyping SLI queries locally.
Recommended starting targets by surface
- Public marketing pages — 99.5% availability, p95 < 2s. Marketing can tolerate brief blips during deploys.
- Authenticated app core — 99.7% availability, p95 < 1.5s. Users notice slowness here first.
- Payment and webhooks — 99.9% correctness, p99 < 3s. Money paths deserve the strictest budget.
- Internal admin — 99.0% availability. Do not burn your error budget protecting low-traffic admin panels.
Document exclusions. Planned maintenance windows, upstream PSP outages, and DDoS mitigation may sit outside the SLO if stakeholders agree in writing. Ambiguity here causes arguments after every incident.
Align SLOs with business hours for regional apps
Nepal-facing booking sites often peak during local evening hours and go quiet overnight. You can define separate SLO windows—stricter during 10:00–22:00 NPT, relaxed otherwise. That matches how support and maintenance teams actually staff incidents without paging someone at 3 AM for a non-critical blip.
Alert on burn rate, not on every threshold twitch. Our guide on SLO-driven alerting that does not page at 3 AM covers multi-window burn alerts in detail.
How do you measure SLIs in a Laravel production stack?
Theory without instrumentation is a slide deck. Here is a practical stack I use on PHP 8.3+ / Laravel 12 and 13 apps behind Nginx or Apache.
Emit metrics at the request boundary
Middleware is the cleanest hook. Count good and bad events with labels you will actually slice by later:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class SloMetricsMiddleware
{
public function handle(Request $request, Closure $next): Response
{
$start = hrtime(true);
$response = $next($request);
$durationMs = (hrtime(true) - $start) / 1_000_000;
$route = $request->route()?->getName() ?? 'unknown';
$status = $response->getStatusCode();
$good = $status < 500 && $durationMs < 3000;
redis()->incr("sli:checkout:total");
if ($good) {
redis()->incr("sli:checkout:good");
}
return $response;
}
}
In production I prefer Prometheus counters exported via redis_exporter or a thin sidecar. The pattern is the same: increment good and total, then compute the ratio in PromQL or Grafana.
Example PromQL for availability and latency SLIs
# Availability SLI over 30d rolling window
sum(rate(http_requests_total{route="checkout.store",status!~"5.."}[5m]))
/
sum(rate(http_requests_total{route="checkout.store"}[5m]))
# Latency SLI: share under 3s
sum(rate(http_request_duration_seconds_bucket{route="checkout.store",le="3"}[5m]))
/
sum(rate(http_request_duration_seconds_count{route="checkout.store"}[5m]))
Log-based SLIs work when metrics are missing. Parse Nginx access logs with Loki or ELK. I have recovered baseline SLIs from logs on legacy CodeIgniter apps before adding modern instrumentation. That unblocks SLO conversations even during a migration.
Track correctness for async work
Queue failures silently eat correctness SLIs. Wrap critical jobs—payment reconciliation, PDF generation, SMS—with explicit success/failure counters:
public function handle(): void
{
try {
$this->processPaymentCallback();
Metrics::increment('job.payment_callback.success');
} catch (\Throwable $e) {
Metrics::increment('job.payment_callback.failure');
throw $e;
} finally {
Metrics::increment('job.payment_callback.total');
}
}
Failed jobs that retry successfully still consumed error budget time. Track end-state outcomes, not attempt counts, unless retries are part of your user promise.
For API-heavy platforms, pair SLI work with API rate limiting and abuse prevention. A traffic spike from scrapers can look like an availability incident if you do not separate abusive 429s from server 500s in your validity rules.
What are common mistakes when defining SLIs and SLOs?
I've audited monitoring on client projects where every chart looked healthy while users complained. The same mistakes appear repeatedly.
- Measuring infrastructure, not experience — CPU under 70% does not prove checkout works. Measure the journey.
- Too many SLOs — Cap at three per service. More than that dilutes attention.
- Chasing 100% — An SLO of 100% is impossible and blocks deploys. Leave headroom.
- No ownership — An SLO without a named owner becomes wallpaper. Assign a DRI.
- Alerting on SLI noise — Page only when burn rate threatens the monthly budget. See Alertmanager patterns for routing.
- Ignoring third parties — Payment gateways and SMS providers fail. Either model them inside correctness SLIs or document them as dependencies with separate monitors.
Deployer 7 symlink swaps on shared EC2 hosts can briefly spike errors if PHP-FPM opcache serves stale bytecode. I treat deploy windows as expected variance only after measuring their actual SLI impact. Often a 30-second blip is cheaper than complex blue-green infrastructure for a law-firm portal. Measure first, then negotiate the SLO.
Teams exploring automation should read AIOps basics with skepticism. ML anomaly detection supplements SLOs; it does not replace them. A model cannot tell stakeholders how many failed bookings are acceptable this month.
How does an error budget connect SLIs and SLOs to release decisions?
An error budget is the complement of your SLO. At 99.5% over 30 days, you accept 0.5% bad events—roughly 3.6 hours of downtime or equivalent failed requests per month. That number is negotiable currency between product and engineering.
When budget remains, ship features and accept deploy risk. When budget is exhausted, freeze releases and fix reliability. This removes subjective fights about whether QA passed. The SLI data decides.
Document the policy in a one-page SLO doc stored next to your runbooks:
- Service name and owner
- SLI query in plain language and PromQL
- SLO target and rolling window
- Error budget policy (what happens at 50%, 90%, and 100% burn)
- Excluded events and dependencies
On Quick And Easy Nepalese Grocery, checkout correctness SLIs drove a decision to add idempotent payment callbacks before expanding delivery zones. The feature freeze was data-backed, not political.
Enterprise clients asking for contractual SLAs should start from internal SLOs that have been met for two consecutive review periods. Promising an SLA before you can measure an SLO is how you end up issuing credits you cannot afford. Our enterprise application development engagements include SLO workshops for that reason.
Infrastructure choices affect whether you can meet targets. Moving from Apache to Nginx without measuring baseline SLIs first is guesswork. Read the migration checklist in our Apache to Nginx guide and compare before/after SLIs, not just load-test RPS.
Redis 8.10 caching, MySQL 9.7 query tuning, and PHP-FPM pool sizing all influence latency SLIs. None of them replace journey-level measurement. They are levers you pull after the SLO proves where time is lost.
Key Takeaways
- Define one SLI per critical user journey—availability, latency, correctness, or freshness—not every server metric on the dashboard.
- Set SLO targets from historical data; 99.5–99.9% is realistic for most small Laravel teams unless you fund redundant infrastructure.
- Measure at the request boundary with middleware, logs, or Prometheus counters using good-events-over-valid-events ratios.
- Alert on error budget burn rate, not raw CPU or memory thresholds, to avoid pointless 3 AM pages.
- Publish a one-page SLO document with queries, owners, and release-freeze rules so product and engineering share the same numbers.
- Revisit SLOs quarterly; tighten targets only after stable compliance, not after a single good month.
People Also Ask
How many SLIs should a microservice or monolith have?
Start with two or three SLIs for the whole application, not per controller. A Laravel monolith might track checkout correctness, authenticated page latency, and nightly report freshness. Split further only when teams independently deploy subsystems with different risk profiles.
Should mobile apps use the same SLOs as the web backend?
The backend SLO covers API availability and latency as experienced by the client. Mobile-specific crashes belong in client-side crash metrics. Align on end-to-end journey SLOs during release reviews, but instrument each tier with its own SLI so blame is actionable.
What window length is best for SLOs—7, 30, or 90 days?
Thirty rolling days is the default Google SRE recommends and what most Grafana SLO plugins assume. Shorter windows react faster but swing wildly on small traffic sites. Ninety days suits seasonal businesses. Match the window to one business planning cycle.
Can you have SLOs without Kubernetes or a full SRE team?
Yes. A single VPS running Laravel, Nginx, Redis, and Prometheus on Ubuntu 24 LTS is enough. SLOs are a discipline, not a platform. Small teams benefit most because error budgets replace endless subjective debates about release readiness.
Turn SLIs and SLOs into a reliability habit
When you define meaningful SLIs and SLOs, you give your team a shared language for quality. Users stop being the monitoring system. Deploys get safer because error budgets gate risk. Start with one journey, one ratio, and one 30-day target this week. Expand after the first review cycle proves the data is trustworthy.
Need help instrumenting a Laravel app, wiring Prometheus, or running an SLO workshop for a Nepal deployment? See our Linux system administration and API development services, or contact us to review your production stack. For related reading, browse more engineering guides or learn how we approach speed optimization alongside reliability work on the homepage.
Frequently Asked Questions
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.

