# OpenAI key boundaries in Next.js
## Rules
1. The key lives in the server environment only. Never prefix it with
`NEXT_PUBLIC_`; that prefix inlines the value into the client bundle at
build time, which is the same as publishing it.
2. All OpenAI calls happen in route handlers, server actions, or server
components. Client components call your route handler, never the OpenAI SDK.
3. Do not import the OpenAI client (or any module that constructs it at import
time) from a client component, even indirectly. The import graph is what
leaks, not just the variable.
4. For Realtime websocket endpoints, pin `export const runtime = "nodejs"`.
Streaming and websocket code in route handlers needs the Node runtime; the
edge runtime cannot hold the upstream socket the same way.
## The failure shape
The symptom is a key that works in development and gets abused in production:
client bundles are public, scrapers extract keys in minutes, and the bill
arrives before anyone notices. There is no alert for "key seen in bundle";
you have to check.
## Check before you ship
- `grep -r "NEXT_PUBLIC" --include="*.ts" --include="*.tsx"` for anything
OpenAI-related; zero hits.
- Build the app and search the `.next/static` output for a fragment of a test
key; it must not appear.
- Confirm every OpenAI SDK import resolves from server-only modules (route
handlers, server components, files importing `server-only`).