ElementsVault

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

src/core/vault.ts
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

src/flows/invites/create.ts
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:

OptionTypeDefaultMeaning
descriptionstringBoot-gap and Console label
rotatestringomitOptional cadence hint (rarely used for config)
schemaSchemaDeclared shape for docs / tooling
devstringDev-only fallback
sensitivebooleanfalseSet 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.

HelperReturnsThrows when
vault.env(name)string | undefined
vault.env.required(name)stringunset — also registers for boot gaps
vault.env.int(name, def?)numberunset without default, or not an integer
vault.env.bool(name, def?)booleanunset without default, or not boolean-shaped
vault.env.json(name)T | undefinedvalue 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

KindConsole listruntime.cleartext(name)runtime.fingerprint(name)
secretFingerprint onlyalways undefineddefined when loaded
configShown in clearloaded valuealways undefined

Both still return Redacted from fx.vault.get — reveal when you need a plain string.

Troubleshooting

Learn more

Next

On this page