Config
vault.config cleartext settings, Console visibility, and vault.env helpers for plain process configuration.
Config contracts (vault.config) hold non-secret operational settings — public origins,
feature flags, workspace labels. They resolve through the same boot chain as secrets, but Console
may show them in the clear.
For developers who need validated settings without fingerprinting — declare vault.config, read
with fx.vault.get, keep credentials on vault.secret instead.
The one rule
Use vault.config only when cleartext in Console and logs is acceptable. API keys, tokens, and
connection passwords belong on vault.secret.
Smallest Example
Declare a config contract
import { vault } from "okengine";
import { z } from "zod";
export const publicAppUrl = vault.config("PUBLIC_APP_URL", {
description: "Public origin for email links and redirects",
schema: z.string().url(),
// Dev-only fallback — never used in prod boot
dev: "http://localhost:6530",
});Read it in a Flow
import { on, flow, http } from "okengine";
import { z } from "zod";
import { member } from "@/core/gate";
import { publicAppUrl, noteCreatedMail } from "@/core";
export const create = on(
http
.post({
in: z.object({ email: z.string().email() }),
})
.gate(member),
flow({
do: async ({ email }, fx) => {
const origin = await fx.vault.get(publicAppUrl);
await fx.send(noteCreatedMail, {
to: email,
// Config may be revealed for URL building — still prefer holding Redacted
// until the send boundary when mixed with secrets
link: `${origin.reveal()}/accept`,
});
return fx.json.empty();
},
}),
);See it in Console
The Config band shows PUBLIC_APP_URL in the clear after boot (secrets stay fingerprinted). Update
via Console write or oke vault set PUBLIC_APP_URL.
Progressive Patterns
From a public URL to flags, registration, and the env escape hatch:
export const publicApiUrl = vault.config("PUBLIC_API_URL", {
description: "Browser-facing API origin",
schema: z.string().url(),
dev: "http://localhost:6530",
});Options Reference
Same option bag as secrets (VaultSecretOptions), with different defaults:
| Option | Type | Default | Meaning |
|---|---|---|---|
description | string | — | Boot-gap and Console label |
rotate | string | omit | Optional cadence hint (rarely used for config) |
schema | Schema | — | Declared shape for docs / tooling |
dev | string | — | Dev-only fallback |
sensitive | boolean | false | Set true only if this config must never show in Console |
Empty name throws TypeError: vault.config: name is required.
Consequence: sensitive: true on a config behaves like a secret for Console cleartext —
prefer vault.secret when that is the intent.
vault.env helpers
Synchronous reads of process environment. Empty strings count as unset.
| Helper | Returns | Throws when |
|---|---|---|
vault.env(name) | string | undefined | — |
vault.env.required(name) | string | unset — also registers for boot gaps |
vault.env.int(name, def?) | number | unset without default, or not an integer |
vault.env.bool(name, def?) | boolean | unset without default, or not boolean-shaped |
vault.env.json(name) | T | undefined | value present but not valid JSON |
Boolean true: 1 · true · yes · on. False: 0 · false · no · off (case-insensitive).
// TypeError: vault.env.required: CI_TOKEN is not set
vault.env.required("CI_TOKEN");
// TypeError: vault.env.int: PORT is not an integer
process.env.PORT = "abc";
vault.env.int("PORT");Reach for vault.secret / vault.config when the value must participate in the resolution chain,
fingerprinting, or Console Vault.
Cleartext vs fingerprint
| Kind | Console list | runtime.cleartext(name) | runtime.fingerprint(name) |
|---|---|---|---|
secret | Fingerprint only | always undefined | defined when loaded |
config | Shown in clear | loaded value | always undefined |
Both still return Redacted from fx.vault.get — reveal when you need a plain string.
Troubleshooting
vault.config is not auto-registered. Pass oke({ secrets: [publicAppUrl] }) or ensure the
declaring module is adopted the same way your app wires secrets.
Same resolution chain as secrets — set the value or provide dev: for local boot. Config gaps
fail boot just like secrets when registered.
Call site threw immediately. For boot-time collection, keep the required call so the name is
registered; boot then lists it with other gaps.
Value is present but malformed. Use the documented boolean tokens, an integer string, or valid
JSON — or supply a default for int / bool when unset is allowed.
You declared vault.config (or sensitive: false). Move credentials to vault.secret.
Learn more
- Secrets — fingerprinted contracts and Redacted
- Vault overview — resolution order and drivers
- Environment variables —
OKE_*knobs - fx —
fx.vault.geton any contract