Environments and secrets
Nola has no environment system of its own. nola.config.ts is plain TypeScript, so environments are plain branching — plus one runtime-enforced switch and a clear rule about where keys come from.
Where keys come from
Section titled “Where keys come from”- Every provider factory reads its API key lazily, at the first request:
openai()fromOPENAI_API_KEY,anthropic()fromANTHROPIC_API_KEY,google()fromGEMINI_API_KEY. Override the variable name withapiKeyEnv: "MY_VAR"or passapiKeyinline (prefer the variable). - In development,
nola runandnode --import nola-lang/registerapply a project-root.envbefore evaluating the config. It follows the dotenv convention: a variable already set in the real environment wins over the file. - In production nothing loads
.env.nola buildoutput reads the real environment of the process — set the variables in your deployment platform.
Environments are plain TS branching
Section titled “Environments are plain TS branching”import { mockProvider, openai } from "@nola-lang/providers";import { defineConfig } from "@nola-lang/runtime";
const production = process.env.NODE_ENV === "production";
export default defineConfig({ providers: { default: openai({ model: production ? "gpt-5" : "gpt-5-mini" }), mock: mockProvider(() => ({ ok: true })), }, // hermetic CI: EVERY ask goes to `mock`, even ones pinned with ask with / .withProvider() forceProvider: process.env.CI ? "mock" : undefined,});forceProvider is the one runtime-enforced mechanism. Because it overrides every pin, a provider chosen inside a dependency cannot leak a real API call into a test run — see Providers and Testing.
Redaction
Section titled “Redaction”Secrets are redacted from everything Nola logs or stores in a receipt — the built-in logger, hook payloads and AskReceipt never carry a raw key. The same helpers are exported for your own logging:
import { redactError, redactSecrets } from "@nola-lang/runtime";
export const safe = (text: string) => redactSecrets(text);export const safeError = (error: unknown) => redactError(error);Never commit keys
Section titled “Never commit keys”- Keep
.envin.gitignore— the starter’s ignore file already lists it besidenode_modules/anddist/; in a retrofitted project, add it yourself. - A replay ledger (
nola.replay.jsonl) contains full prompts and answers. It is meant to be committed for deterministic tests — review what your contextual parameters put into it first. - Keys never belong in
nola.config.ts; the file is bundled intodist/nola.config.jsbynola build.
Next: Observability