Environments and secrets
Use ordinary TypeScript conditions in nola.config.ts to choose settings for development, CI and production. Keep API keys in environment variables, and use forceModel when every ask in a test run should use a mock.
Where keys come from
Section titled “Where keys come from”- Provider factories read API keys at the first request:
openai()usesOPENAI_API_KEY,anthropic()usesANTHROPIC_API_KEY,google()usesGEMINI_API_KEY, andmodel: "nola"usesNOLA_API_KEY. The scaffold writes the Nola key when you choose the free runs. To use another variable, setapiKeyEnv: "MY_VAR"; for the platform, usenola.infer({ apiKeyEnv: "MY_VAR" }). Factories also accept anapiKeyoption. NOLA_API_URLchanges the endpoint used by the platform model,nola.tracer(), the scaffolder’s trial request andnola account. Use it for development.nola runandnode --import nola-lang/registerload the project-root.envbefore evaluating the config. Variables already set in the process environment take precedence.- The output of
nola buildreads the process environment and does not load.env. Set production variables through 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({ model: { 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 / .withModel() forceModel: process.env.CI ? "mock" : undefined,});forceModel overrides every model selection, including choices made inside dependencies. In this example, all asks use mock when CI is set. See Providers and Testing.
Redaction
Section titled “Redaction”Nola redacts secrets from built-in log output, the receipt’s outcome.error and the record ledger.
Composed prompts are not redacted. Hooks receive the request and response as sent, and the receipt’s originalPrompt and effectivePrompt contain the full conversation. A secret passed as a contextual value can therefore appear in those fields. Keep secrets out of contextual parameters.
For your own logging, use the exported redaction helpers:
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
.envand.env.*in.gitignore. Scaffolded templates already include both; add them when setting up an existing project. The trial step also adds these entries. - A replay ledger (
nola.replay.jsonl) contains prompts and answers. Review its contents before committing it for tests. - Keep keys out of
nola.config.ts, whichnola buildbundles intodist/nola.config.js.
Next: Observability