# Secrets inventory (/docs/maintain/security/secrets)

- **Status:** Current
- **Last updated:** 2026-11-01
- **Related ADRs:** ADR-0005, [ADR-0016](../adr/ADR-0016-home-search-is-the-fumadocs-dialog-and-private-projects-render-server-side.mdx)

> Snapshot of the system as it stands today. Edit in place; never record what changed.

## Inventory [#inventory]

The variables are read directly where they are used. Locally they live in `.env.local`, which
`.gitignore` excludes (`.env*.local`). `.env.example` at the repository root lists every
variable below, with a comment and no value.

| Variable | What it is | Secret? | Reaches the browser? | Read by | Rotation |
|---|---|---|---|---|---|
| `SITE_URL` | The site's public address, an `https` origin with no path; without it every page is `noindex` (ADR-0035) | No — public, and printed on every share image | Only as the address in pages' links and images; never as a variable | `src/lib/seo.ts`, `src/app/og/[...slug]/route.tsx`, `scripts/sync-content.ts` | When the domain changes |
| `NEXT_PUBLIC_ALGOLIA_APP_ID` | Algolia application ID | No | **Yes**, inlined into the client bundle | `src/lib/algolia.ts`, `scripts/sync-content.ts` | With the Algolia application |
| `NEXT_PUBLIC_ALGOLIA_SEARCH_KEY` | Algolia search-only API key | No — public by design, but it can read **every record** in the index | **Yes**, inlined into the client bundle | `src/lib/algolia.ts` | On suspicion of abuse, in the Algolia dashboard |
| `ALGOLIA_WRITE_KEY` | Algolia key with write access to the index | **Yes** | No | `scripts/sync-content.ts` only | On suspicion, or yearly, in the Algolia dashboard |

## Rules [#rules]

- **No secret is ever a string literal** — not in source, config, comments, tests or docs.
- **`NEXT_PUBLIC_*` publishes a value to every browser.** Never a secret; each one is reviewed
  as a publication. `ALGOLIA_WRITE_KEY` must never gain the prefix.
- **`.env*.local` files stay out of git.** `.env.example` is committed and documents every
  variable with a comment, never a value.
- **A build that publishes refuses to run without the secrets it needs**, naming the variable
  and never printing its value. `scripts/sync-content.ts` refuses in the same way without `SITE_URL`,
  so production cannot silently go `noindex`.
- **If a secret is ever committed, rotate it immediately.** Removing it from the tree or from
  history is not enough.
