The three layers
If you find yourself editing component source to change copy, stop —
you should be editing
messages/{en,zh}.json instead.
What siteConfig controls
The whole file is ~250 lines. Here are the load-bearing fields:
What lives outside siteConfig
These have their own homes — by design.
Adding a new feature flag
-
Add to
siteConfig.features: -
Reference in code:
Adding an env var
- Add a Zod-validated entry in
src/env.ts(server section if it’s secret; client section if it has theNEXT_PUBLIC_prefix and is safe to ship to the browser). - If it’s a public var, add it to
experimental__runtimeEnvtoo (Next.js requires this). - Document it in Env reference.
- Use
import { env } from '@/env'to read it — neverprocess.env.Xdirectly.
Best-practice checklist
- ✅ Brand changes happen in
siteConfigandmessages/. No component-source edits. - ✅ Secrets only in
.env.local. The.env.exampledocuments the shape; the real.env.localis gitignored. - ✅ When swapping a provider (Stripe → Creem), change
siteConfig.payment.providerAND set the matching*_PRICE_*env vars. The rest of the app doesn’t care which provider is active. - ✅ Both
messages/en.jsonandmessages/zh.jsonalways have the same keys.node scripts/check-i18n.mjsenforces this.