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.

Define Meaningful SLIs and SLOs

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.

SLI, SLO, and SLA RelationshipSLIMeasured signalSLOInternal targetSLAContract promiseError Budget = 100% minus SLO targetBudget spent on failed requests, slow pages, bad deploys
Define meaningful SLIs and SLOs first; add an SLA only when contracts require customer-facing penalties.

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.

TermWho caresExampleTypical owner
SLIEngineering99.2% of checkout requests succeed in < 2sDev + ops
SLOProduct + engineering99.5% success over 30 daysTeam lead
SLACustomer + legal99.0% uptime or 10% creditAccount 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.

Choosing an SLI by Journey TypeMap user journeyRead-heavy pageLatency SLIWrite / paymentCorrectness SLIBackground jobFreshness SLIp95 < 1.5s target99.9% success95% within 5 minAttach SLO + error budget per SLI
Match SLI type to journey shape—latency for reads, correctness for writes, freshness for async work.

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.

  1. Public marketing pages — 99.5% availability, p95 < 2s. Marketing can tolerate brief blips during deploys.
  2. Authenticated app core — 99.7% availability, p95 < 1.5s. Users notice slowness here first.
  3. Payment and webhooks — 99.9% correctness, p99 < 3s. Money paths deserve the strictest budget.
  4. 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.

Error Budget Burn Over 30 DaysDay 0Day 30100%0%Healthy burnFast burn — page on-callSlow burn — ticketSLO 99.5% = 0.5% budget (~3.6 h / month)
Error budget burn rate tells you whether to page immediately or open a next-day ticket—core to SLO-driven alerting.

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.
SLI Measurement PipelineUserBrowserNginxAccess logLaravelMiddlewareRedisQueuePrometheus / Loki — store good and total eventsGrafana SLOBurn rate panelsAlertmanagerPage or ticket
Production SLI pipeline for Laravel: capture at the edge and app layer, aggregate in Prometheus, decide in Grafana.

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

An SLI measures user-perceived quality. An SLO is your internal target for that indicator. An SLA is a contractual customer promise, often with credits or penalties.

Start with critical user journeys that drive support tickets or lost revenue, not server dashboards. Map flows like browse, checkout, payment callback, document upload, or PDF generation, then assign at most one primary SLI per step. Match indicator type to journey shape: availability for successful responses, latency for reads using percentiles, correctness for business outcomes like captured payments, and freshness for async work like report exports. Write the good-events-over-valid-events ratio in plain language before touching Prometheus or CloudWatch.

Start around 99.5% over 30 rolling days if historical data supports it. Promising 99.99% on a single VPS usually sets you up for permanent firefighting.

Emit metrics at the request boundary with middleware that records duration, status code, and route name. Increment good and total counters in Redis or Prometheus, then compute ratios in PromQL or Grafana. For availability, count non-5xx responses; for latency, count requests under your threshold such as three seconds. Wrap critical queue jobs like payment callbacks, PDF generation, and SMS with explicit success, failure, and total counters so async failures do not silently eat correctness. Log-based SLIs from Nginx access logs via Loki or ELK work when counters are not yet deployed.

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. When budget remains, ship features and accept reasonable deploy risk. When budget is exhausted, freeze releases and fix reliability. That replaces subjective fights about whether QA passed with numbers the SLI data supports. Document what happens at 50%, 90%, and 100% burn in a one-page SLO doc stored next to your runbooks, including excluded events and upstream dependencies.

The same failures appear repeatedly on client audits: measuring infrastructure like CPU instead of user journeys, defining too many SLOs, chasing 100% targets, leaving SLOs without a named owner, and paging on every metric twitch instead of burn rate. A low CPU reading does not mean checkout works. Cap at about three SLOs per service. Either model payment gateway and SMS provider failures inside correctness SLIs or document them as dependencies. Measure deploy blips from symlink swaps before treating them as expected variance. ML anomaly detection supplements SLOs but cannot tell stakeholders how many failed bookings are acceptable this month.

Start with two or three SLIs for the whole application, not one per controller. A typical Laravel monolith might track checkout correctness, authenticated page latency, and nightly report freshness. Split further only when independently deployed subsystems have different risk profiles and teams. Measuring everything produces alerts nobody trusts. On projects combining Livewire booking with supplier CRM sync, that naturally yields separate latency and freshness SLIs because one dashboard cannot represent both priorities without blurring them.

Alert on error budget burn rate, not raw CPU, memory, or every threshold twitch. Dashboards can show green CPU while customers report checkout timeouts on Friday evenings. Burn rate tells you whether monthly budget loss warrants an immediate page or a next-day ticket. Multi-window burn alerts avoid pointless 3 AM pages for brief blips. Infrastructure metrics still help debugging after an SLI breach, but they should not be your primary paging signal for user-facing reliability.

Average latency hides slow outliers that still ruin a session. One request taking twelve seconds can sit buried in a mean while users suffer. Use p95 for user-facing pages and p99 for payment and webhook endpoints where tail latency matters most. Define good events as requests faster than your threshold, then express the SLI as the fraction meeting that bar. Google SRE framing treats SLIs as ratios of good over valid events, which prevents vanity metrics that look healthy while experience degrades.

Wrap critical async jobs such as payment reconciliation, PDF generation, and SMS delivery with explicit success, failure, and total counters at end state, not per retry attempt. A job that fails twice then succeeds still consumed error budget time during the outage window. Track whether the business operation completed correctly, not how many queue attempts ran. Payment paths deserve stricter targets than marketing pages, typically 99.9% correctness with p99 latency under three seconds on webhook endpoints.

Export 30 to 90 days of access logs or APM data and calculate your current SLI before committing. Suggested starting points: public marketing pages at 99.5% availability with p95 under two seconds; authenticated app core at 99.7% availability with p95 under 1.5 seconds; payment and webhooks at 99.9% correctness with p99 under three seconds; internal admin at 99.0% availability. Do not burn error budget protecting low-traffic admin panels. Document exclusions for planned maintenance, upstream payment provider outages, and DDoS mitigation if stakeholders agree in writing.

Parse Nginx or Apache access logs with Loki or ELK to reconstruct availability and latency ratios when Prometheus counters are not yet deployed. Baseline SLIs recovered from logs unblock SLO conversations during migrations on legacy apps. Apply the same good-over-valid framing: exclude client aborts like 499 responses unless you explicitly own connection stability, and separate abusive 429 rate-limit responses from true server 500 failures so scrapers do not look like an availability incident. Pair this with API rate limiting so traffic spikes do not distort your validity rules.

Either model gateway failures inside correctness SLIs or document them as external dependencies with separate monitors. Ignoring third parties makes your SLO look broken when the payment service provider times out even though your Laravel code is fine. Stakeholders need clarity on what your team owns versus what sits upstream. On a grocery checkout project, correctness SLIs drove adding idempotent payment callbacks before expanding delivery zones because failed callbacks were eating real error budget. Measure end-to-end user outcomes, then negotiate exclusions only with written agreement.

Yes, and regional apps often should. Nepal-facing booking sites peak during local evening hours and go quiet overnight. Define stricter targets during 10:00 to 22:00 NPT and relaxed targets otherwise so support staff are not paged at 3 AM for non-critical blips. Align SLO windows with when users depend on the service and when your team can respond. This fits small teams without overnight on-call rotation and matches how maintenance windows are already scheduled.

Add an SLA only when a contract demands customer-facing penalties. Start with internal SLOs first and prove you can measure them for two review periods before promising credits.

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: