Skip to content

Testing in Production

Testing in production means deliberately verifying behaviour in the live environment, under real traffic, real data and real infrastructure. It is the concrete form of shift-right testing.

The phrase sounds reckless and is not, provided the groundwork exists. What is reckless is the alternative that most teams practise by default: releasing to production and finding out from users.

graph LR
    PRE[Pre-production testing] --> LIMIT["Limits: synthetic data, small scale, simulated dependencies"]
    PROD[Production] --> REAL["Real traffic, real data, real failure modes, real users"]
    LIMIT --> GAP[The gap where escaped defects live]
    REAL --> CLOSE[Closing the gap deliberately, with controls]

The practices

Practice What it verifies Main control
Post-deploy smoke checks The deployment is live and serving correctly Automatic rollback on failure
Synthetic monitoring Critical journeys work right now, including at low-traffic hours Alerting on failure
Canary release A new version behaves on a small traffic share Metric thresholds, automatic rollback
Dark launch New code handles real load before its output is shown Output discarded, comparison logged
Feature flags Exposure controlled per user, cohort or percentage Kill switch without a deploy
A/B experiment Whether the change improves the intended outcome Predefined metrics and duration
Chaos experiment Resilience mechanisms work against real failure Small blast radius, automatic abort
Monitoring and alerting Continuous verification against real usage Symptom-based alerts, error budgets

Dark launching, worth understanding

graph LR
    REQ[Real request] --> OLD[Existing implementation]
    OLD --> RESP[Response returned to the user]
    REQ --> NEW[New implementation, in parallel]
    NEW --> CMP[Compare results and record differences]
    CMP -.->|user never sees this| RESP

The new code path handles genuine production traffic, at full scale, with real data, while the user still receives the old result. Differences are logged and analysed. For risky rewrites of pricing, search or ranking logic this gives evidence that no staging environment could produce.

The preconditions

Testing in production without these is not a strategy, it is an outage schedule.

Precondition Why
Observability Without traces, metrics and logs you cannot tell what happened
Fast, tested rollback Everything else depends on being able to undo quickly
Feature flags with a kill switch Withdraw exposure without waiting for a deploy
Defined thresholds and error budgets "Is this acceptable" decided beforehand, not during
Small blast radius Percentage rollouts and internal cohorts first
Test data hygiene Synthetic traffic must not create real charges, emails or records
Incident response Someone is watching, and knows what to do

The test data row causes real damage when it is skipped. Synthetic journeys that place real orders, send real emails or hit real payment endpoints have all happened, and each of them is a self-inflicted incident.

What it does not replace

Production verification finds what pre-production cannot. It does not substitute for cheap early checks, because finding in production a defect a unit test would have caught means paying the highest possible price for it. The two ends of the pipeline cover different classes of problem, and a team that leans entirely on either one is exposed on the other.

Check Your Understanding

#

What does dark launching verify that a staging environment cannot?

#

Which precondition is most often skipped and causes self-inflicted incidents?