Technote

Development workflow Practical

Series From local to production Part 5 of 8

If staging differs from production, your tests are lying

Staging does not need to be a similar environment; it needs to be identical in the ways that matter. Which ways those are can be written down as a list.

There is exactly one reason to keep a staging environment: to see the result before you deploy it. If staging differs from production, that preview is a preview of a different site. Either it passes and production breaks, or it breaks only on staging and you spend hours chasing a problem that does not exist.

“Completely identical” is usually impossible and rarely necessary. What you actually need to decide is which differences change the outcome.

What must match, and what must not

Designing staging — when the right column drifts, the test result cannot be trusted

Each item on the right fails in its own way. A different PHP version changes deprecation notices and type handling, so code that was quiet on staging starts complaining in production. A missing extension sends the feature down an entirely different code path. Database version and sql_mode are the quietest of all: an INSERT rejected under strict mode passes happily under a looser one.

Caching layers lie in both directions. If only production has an object cache, an N+1 query pattern you caught on staging disappears in production. If only production has a page cache, the “logged-in visitors are served a cached page” bug appears exclusively in production.

Comparing takes a handful of commands

Print the same facts on both sides and diff them. The habit turns “is it the environment?” from a suspicion into a checked fact.

wp --info
wp db query 'SELECT VERSION();'
wp db query 'SELECT @@sql_mode;'
wp eval 'echo implode( PHP_EOL, get_loaded_extensions() );' | sort
wp plugin list --status=active --field=name | sort
wp eval 'echo ini_get( "memory_limit" ), " ", ini_get( "max_execution_time" );'

Keeping staging from causing an incident

Staging holds a copy of real data, so left alone it will email real customers and get itself indexed. Both must be prevented in code. Relying on someone remembering to switch them off means one day nobody does.

<?php
// wp-content/mu-plugins/staging-guard.php

if ( 'production' !== wp_get_environment_type() ) {
    // short-circuit delivery and report success (WP 5.7+)
    add_filter( 'pre_wp_mail', '__return_true' );

    // force it at read time, not in the option — survives a fresh DB import
    add_filter( 'pre_option_blog_public', '__return_zero' );
}

The second filter matters because it intercepts the read rather than editing the option. Re-import the production database and the value does not come back to life. Add HTTP basic auth or an IP restriction on top and the staging URL has no route into search at all.

Data volume is part of the environment

One axis gets forgotten more than any other: a staging site with twenty posts cannot reproduce a problem that only appears at two hundred thousand. Archive queries, indexes and sitemap generation all scale with content. Pulling a sanitised copy of production data down, using the procedure from part four, is the only practical way to match this axis.

How the measuring and verification actually run is published step by step on our process page, and the performance background sits in the Performance archive.

Next part

Once staging says yes, it is time to move the code. The next part covers three deploy strategies — rsync, git on the server, and shipping a built artefact — and what separates them is not speed but the rollback story.

More on this topic

All technotes

Development workflow Advanced

The design QA checklist to run before release

Most design problems found after release are catchable before it, in order. Here is the pass, in three stages: rules, states and real devices.

Designers 6 min read

Development workflow Advanced

Never deploy without a way back

A rollback is not one button. It is two tracks — code and database — with an order to reverse them in, written down before you deploy.

Designers 9 min read

Development workflow Advanced

Adding your own hooks: extension points instead of edits

Code with no extension points gets forked or edited in place. Where you put do_action and apply_filters — and how many — decides how long that code survives.

Developers 7 min read

₩270,000 · Join the program