robots Must Match Access Intent
MUST: The `robots` meta must match actual access intent, so DERIVE it from the environment instead of hardcoding: default to `noindex` and let exactly one environment opt in (`process.env.VERCEL_ENV === "production"`). Preview and staging deploys are public URLs nobody thinks of as public, and an indexed staging copy competes with production for your own brand name. The symmetric failure is the overcorrection: a hardcoded `noindex` merges and production silently deindexes itself — deindexing is quiet, traffic just stops. Reserve `noindex` for private, duplicate, or non-public pages.
Derive the robots tag from the deploy environment: noindex by default on previews and staging, index only where the page is genuinely public
const isProd = process.env.VERCEL_ENV === "production";
<meta name="robots" content={isProd ? "index,follow" : "noindex,nofollow"} />Bad
Good
Why it matters
From the canonical and indexing rules in ibelick's fixing-metadata skill. Preview deploys are public URLs that nobody thinks of as public. Leave them indexable and a crawler will eventually find one, at which point a half-finished staging copy of your site is competing with production for your own brand name — and because it is thinner, newer, and often a near-duplicate, the outcome is unpredictable in exactly the way you cannot afford.
That is the expensive, common failure. The symmetric failure is what people ship when they overcorrect: someone hardcodes `<meta name="robots" content="noindex">` to fix staging, it merges, and production quietly deindexes itself. Nobody notices for weeks, because deindexing is silent — traffic just stops. Both failures come from treating robots as a static tag rather than a function of the environment.
Derive it: default to noindex and let exactly one environment opt in (`process.env.VERCEL_ENV === 'production'`). Defaulting to noindex means every new preview surface is safe on the day it ships, and the single env that opts in is the one place you can actually check.