Method & operations
If you are searching for a staging environment, or for preview vs staging, you are usually here: you have preview deploys on every pull request, and someone has said you 'need staging'. Or you already have a staging nobody has touched in months, and you still deploy straight to production because staging lies. Someone creates a second Vercel project and calls it done. Someone copies production with real keys. Someone refuses to merge until 'it has sat on staging'.
The CI/CD post is about preview before merge: a clickable branch, a review that is not blind. This one is about the third environment — the long-lived, shared one that should behave like production. An honest staging environment is not a hotel for branches. It is a truth you can point at when preview cannot hold it: a webhook that can only point one place, a payment sandbox, an ERP, content you need to freeze, a data shape that only shows up with real rows.
TL;DR
The main points
- Preview is a review of a branch. Staging is a shared environment that should resemble production.
- Most marketing sites do not need staging if every pull request has a preview and production is the only shared truth.
- You need staging when something cannot exist per pull request: a webhook, payments, an ERP, editors without GitHub, a migration you must dry-run.
- A staging that is empty, stale, or a dump for unreviewed work is worse than no staging.
- Preview plus production is two jobs. Staging is a third — pay for it only when you can name the job.
- Do not call an extra URL staging if it has no data, no integrations and no owner.
Why this matters at all
A staging you cannot explain costs weeks you call 'quality assurance'. People merge because 'it sat on staging', and discover in production that the webhook still pointed at the old URL, that the Stripe key was test, or that the content was three months old. You think you have a gate. You have a ritual. The ritual is expensive because it gives you permission not to look.
Teams inherit staging from another kind of software. In a bank, an ERP, a monolith with one deploy window a month, a long environment before production is survival. On a Next.js site with preview on every pull request it is often theatre: you pay to keep a third site alive that no editor opens and no developer trusts. Preview solved the visual job. Staging has to solve something preview cannot.
It is also a trust and data question. If staging has production data, you have another production you do not guard. If staging is empty, you only fail the queries that die with real rows — in production. If nobody owns refreshing it, it diverges — and then the green 'it worked on staging' is a lie you write in a ticket.
We write this because 'we need staging' has become a purchase you make before you have a sentence about what preview cannot do. An honest setup is boring: preview on every branch, production as the truth, and a third environment only when you can point at the integration, the data shape or the editor who cannot live in a PR URL. Without that sentence you have an extra hostname. You do not have staging.
What a staging environment actually is — and what it is not
A staging environment is a long-lived, shared place that should answer like production in the ways you are actually afraid of. The same kind of database shape. The same kind of auth. The same webhooks, pointing at this URL. The same payment sandbox. Content editors can click through without touching live. It does not have to be a bit-for-bit copy. It has to be a copy of the truths that can break you.
It is not a preview. A preview dies with the pull request. It has the branch's code, often the branch's migrations, and typically not your real Stripe webhook or your ERP. It is for seeing and clicking before you merge. It is the right tool for 'does this look right' and 'does it build'. It is the wrong tool for 'can the payment provider find its way back' and 'can the editor practise without publishing live'.
It is also not production with `noindex` and another hostname. Mirroring live with real customers and real secrets, then calling it staging, is how you get a leak and a second prod you forget to patch. Staging may resemble. It must not be the same valuable thing. An anonymised slice, sandbox keys, a dataset you can afford to lose.
And it is not docker-compose on one laptop. Local is for developing. Staging is for sharing a truth with someone who does not have your laptop: another developer, an editor, a payment vendor, a migration window. If only one person can start it, it is not an environment. It is a hope.
What typically goes wrong when someone says we have staging
The first failure is that staging is stale. The last real deploy was in the spring. The schema does not match prod. Feature flags point elsewhere. You are 'testing' a different product. The only thing staging then catches is that you can log in to a site you will not launch. Refresh it on a rhythm, or drop it. A museum is not a gate.
The second failure is that staging has production keys. The database is yesterday's dump. S3 is the real bucket. Mail sends to real customers if someone clicks. That is not thoroughness. That is another prod without the guard you have on the real one. Sandbox and anonymisation are boring. They are the reason staging is allowed to exist.
The third failure is an empty staging. No rows, no webhook, no editor account, no 'real' integration — just the same Next.js build pointed at an empty Postgres. Then you catch the bugs an empty site can show, and miss the ones that only die with data. If the job is the data shape, give it data. If the job is layout, use preview.
The fourth failure is using staging as a dump. Everything unreviewed lives there. No preview. No pull request. 'It is on staging' means 'someone pushed to a branch we share'. Then you have turned review off and a hotel on. Preview deploys are what keep review alive. Staging is what keeps the shared truth. Mix them and you get neither.
Preview vs staging — two environments, two kinds of truth
Preview on the pull request
A branch you can click. Dies when the PR closes. Review, not a copy of operations.
- One URL per change — designers and product can see the branch
- Built by CI; no shared database you have to guard
- Catches layout, broken links, most rendering bugs
- Cannot hold a fixed webhook, an ERP or an editor rehearsal
Honest staging
A long-lived, shared environment that resembles production in the ways you are afraid of.
- The same hostname for weeks — vendors and editors can bookmark it
- Sandbox keys, a data shape you can afford to lose, an owner who refreshes it
- Catches integrations, migrations and 'does it work with real rows'
- Is waste if the only fear was 'does the home page look right'
How to decide whether you need staging at all
Without this order you get an extra URL you call a gate.
- 01
Write the job staging would hold — in five lines
Not 'we need another environment'. 'The payment provider can only point one webhook.' 'The editor must practise without hitting live.' 'We need to dry-run a migration on something that resembles prod.' 'The ERP has one sandbox endpoint.' If you cannot say the job, you are not ready for staging. You are ready to use the previews you already have.
- 02
Check whether preview already does the job
Layout, copy, most bugs, 'does it build', stakeholder review: that is preview. A marketing site on Next.js and Vercel or Cloudflare, without fixed callbacks, rarely has a third job. If the answer is 'we want to be sure', write what you are afraid of. Safety without a name is how you buy a hotel.
- 03
List the integrations that cannot exist per pull request
Webhooks with one callback URL. A payment sandbox. An ERP. An IdP app you must not create ten of. A sitemap tool that crawls one hostname. Those are candidates for a long-lived environment. If the list is empty, staging is a wish. If the list is long, staging is a system — and then you also have to write which keys are sandbox.
- 04
Decide data: empty, an anonymised slice, or 'we dare not'
Empty staging is honest when the job is the integration, not the rows. An anonymised slice is honest when queries die without volume. Production data is almost never honest. If you dare not make the slice, you do not have a staging problem. You have a data problem to solve before you copy anything.
- 05
Give it a name, a rhythm, and a kill date if the job disappears
Owner is a human, not 'devops'. Rhythm is how it does not become a museum: deploy after prod, or a fixed week, or 'before every migration'. If the webhook moves to something that can be per-PR, shut staging off. An environment without a kill criterion is how you pay for it next year after the job died.
“You have a staging environment when you can name the truth it holds. An extra URL is a hotel.”
Marketing site, WordPress and an app with webhooks — same word, three jobs
A marketing site on Next.js with preview on every pull request typically has two truths: the branch you look at, and production. Editors, if you have them, publish in prod or through a CMS with its own preview. A third environment here is often a place you forget to set environment variables, and then 'it works on staging' means 'it worked without the secrets prod has'. Don't. Use preview. Keep prod boring.
A WordPress site is a different kind. The content is the database. A preview of a theme repo is not the same as 'the editor can press a front page without hitting live'. Here a staging — a copy of the CMS with sandbox keys and a noindex — can be right if you actually rehearse content and plugin updates there. That is still not an excuse to copy real users or to let staging be where you discover the plugin sent the mail.
An app with Stripe, webhooks or an ERP often has the job preview cannot do: the vendor can only point one place, and you need to complete a purchase or a sync without touching live. Then staging is right. Then sandbox keys are the duty. Then 'we pushed to staging and forgot to update the webhook' is the failure you should design out of — one documented URL, one owner, one checklist before you call it tested.
A migration — WordPress to Next.js, a schema change, a cutover — is the week staging earns its keep. Dry-run on something that resembles. Point DNS temporarily if you must. Write what has to be true before you switch. Preview of the new site is still useful. It does not replace having run the boring copy once before customers do.
What you should typically do in the situation you are in
The left is what you typically say. The right is the next step we typically recommend.
Situation
We have preview on every PR and also want staging
Next step
Write the job preview cannot do. If you cannot, the third environment is a hotel
Situation
A vendor can only point one webhook or one sandbox URL
Next step
Then you have the job. One long-lived environment, sandbox keys, an owner — not ten previews you ask them to switch between
Situation
Staging is empty, and we still test there before prod
Next step
Either give it the data shape you are afraid of, or test in preview and prod. Empty staging is an alibi
Situation
We have production data on staging 'so it is realistic'
Next step
That is another prod. Anonymise or shut it off. Realism that can leak is not quality assurance
Situation
Nobody opens staging, and we merge anyway
Next step
Shut it off or fix it. A gate you ignore is more expensive than two honest environments
Checklist before you call it a staging environment
If you are missing several of these, the sentence is staging — the setup is an extra hostname.
- You can say which job staging holds that preview cannot
- The keys are sandbox, and the data is something you can afford to lose
- There is a named owner and a rhythm, so it does not become a museum
- Webhooks and vendors point here on purpose — not 'we forgot to switch back'
- People actually open it before you call something tested
- You know when you will shut it off if the job disappears
Questions we get again and again
When do we need a staging environment?
When something cannot exist per pull request: a webhook with one callback, a payment sandbox, an ERP, editors who must practise without hitting live, or a migration you have to dry-run. If the job is layout, copy and 'does it build', preview is enough. Most marketing sites on Next.js have the latter job, not the former. Write the sentence. If you cannot, do not buy the third hostname.
Are preview deploys the same as staging?
No. Preview is a review of a branch. It dies with the pull request. Staging is a long-lived, shared environment that should resemble production in the ways you are afraid of. We have written about preview in the CI/CD post — clickable review, not a hotel. Mix them and you get unreviewed work on a shared URL, or a staging you use instead of looking at the branch. Two jobs. Two tools.
May staging have an extract of production data?
An anonymised slice you can afford to lose can be right when queries only die with volume. A dump with real customers, mails and secrets is another prod. If you cannot anonymise, you have not made staging safe — you have copied the risk. Empty staging is more honest than a dump you do not guard, if the job was a webhook or a layout anyway.
Does a small Next.js site on Vercel need staging?
Rarely, if every pull request has a preview and you do not have a vendor with one fixed callback. Vercel and Cloudflare make preview cheap. That is why staging has become the wrong default. Add the third environment the day you can point at the integration. Until then, production plus preview is the honest setup — and an extra project is a place environment variables drift apart.
What do we do with a staging nobody uses?
Shut it off, or give it a job and an owner. A museum costs attention: people think it counts until it doesn't, and then prod is what tests. If you shut it off, say so out loud so nobody thinks you still have a gate. If you keep it, set the rhythm — deploy after prod, or only before migrations — and delete it the week the job disappears. An environment without a kill date is a subscription to a lie.
If you have an extra URL and still deploy blind
Let us separate preview, staging and production.
A named job beats a third environment you create because someone said you should.
