Skip to content

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.

  • Provider factories read API keys at the first request: openai() uses OPENAI_API_KEY, anthropic() uses ANTHROPIC_API_KEY, google() uses GEMINI_API_KEY, and model: "nola" uses NOLA_API_KEY. The scaffold writes the Nola key when you choose the free runs. To use another variable, set apiKeyEnv: "MY_VAR"; for the platform, use nola.infer({ apiKeyEnv: "MY_VAR" }). Factories also accept an apiKey option.
  • NOLA_API_URL changes the endpoint used by the platform model, nola.tracer(), the scaffolder’s trial request and nola account. Use it for development.
  • nola run and node --import nola-lang/register load the project-root .env before evaluating the config. Variables already set in the process environment take precedence.
  • The output of nola build reads the process environment and does not load .env. Set production variables through your deployment platform.
nola.config.ts
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.

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:

log.ts
import { redactError, redactSecrets } from "@nola-lang/runtime";
export const safe = (text: string) => redactSecrets(text);
export const safeError = (error: unknown) => redactError(error);
  • Keep .env and .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, which nola build bundles into dist/nola.config.js.

Next: Observability