Menu

Guides

View as Markdown

Configuration & environment

Use this page when you are wiring a new app, moving from local PGlite to deployed Postgres, or trying to answer "which env var does this surface actually read?" The smallest path is to validate your own required env at boot and let the framework refuse early.

Validate your env at boot#

Start with the app-owned vars you actually need:

ts
import { defineKovo, s } from '@kovojs/server';

const app = defineKovo({
  env: s.object({
    STRIPE_SECRET_KEY: s.string().pattern(/.+/),
    SENTRY_DSN: s.string().url().optional(),
  }),
});

export default app.assemble({});

That check happens at boot, not on the first live request. In production, invalid env blocks app assembly. In development, the framework warns instead of bricking localhost.

Run it#

You can see the same failure mode with a missing framework secret by starting the app in production without a real CSRF secret:

sh
NODE_ENV=production pnpm dev

The boot path reports a typed assembly error instead of failing later from inside a route or mutation.

Understand the production shape#

Boot mode comes from NODE_ENV unless an adapter overrides it. The practical differences are:

  • Production refuses weak or missing framework secrets.
  • Development warns about advisory issues instead of throwing.
  • The default outbound egress floor is stricter in production.

The secret floor applies to the framework-owned signing material you wire through defineKovo, not every random string in your process env.

Use the app-facing variables#

These are the env vars you will usually touch in app code, deploy config, or CI.

Every Postgres URL must explicitly name its login, database, and decimal port. Non-local runtime, admin, and system URLs must also use a DNS hostname and exact sslmode=verify-full. Kovo validates this before opening a connection and does not fill destination or identity fields from ambient PG* variables. Only exact 127.0.0.1, an exact query-host ::1, and validated Unix-socket targets may omit TLS for local development. Write the IPv6 control as postgres://app@localhost:5432/db?host=%3A%3A1; Kovo rejects bracketed authority [::1] because pinned pg passes those brackets to DNS. A process booted with NODE_TLS_REJECT_UNAUTHORIZED=0 cannot use a non-local managed Postgres URL.

Variable Used by What it does
KOVO_CSRF_SECRET defineKovo({ csrf }), starter auth Framework signing secret for browser mutation CSRF when you wire it through app config.
KOVO_DATABASE_URL runtime DB, egress bootstrap Ordinary least-privilege app login.
KOVO_RUNTIME_DATABASE_URL kovo db provision / kovo db migrate / kovo db check Runtime witness used for grants and posture. Usually the same login as KOVO_DATABASE_URL.
KOVO_ADMIN_DATABASE_URL kovo db generate / kovo db migrate / kovo db provision / fallback check Privileged setup and fallback-check authority. Keep it out of the app process.
KOVO_DB_SYSTEM_URL app boot, replay/auth storage, boot posture, kovo db check Dedicated system login and preferred check authority on the same writable primary.
KOVO_DB_DRIVER Postgres/PGlite runtime and kovo db Chooses pglite, pg, or node-postgres.
KOVO_DATA_DIR PGlite runtime and starter template Overrides the local PGlite directory.
KOVO_DB_READER_ROLE Postgres provision/check Reader role name. Defaults to kovo_reader.
KOVO_DB_WRITER_ROLE Postgres provision/check, durable tasks Writer role name. Defaults to kovo_writer.
KOVO_DB_ADMIN_ROLE audited crossOwnerRead(...) posture Admin role for the narrower cross-owner read path.
KOVO_DB_SYSTEM_ROLE framework replay/auth storage System role name. Defaults to kovo_system.
KOVO_PRESET kovo build Forces node, vercel, or cloudflare instead of host autodetection.
KOVO_PARANOID build/dev diagnostics Turns on advisory extra security auditing.
KOVO_SQL_GUARD raw SQL migration escape hatch Temporary fail-open escape for unmanaged raw SQL sinks.
KOVO_DEVTOOL_BASE devtool mount Prefixes emitted devtool URLs when you serve it under a subpath.

Two more names matter even though they are not KOVO_*:

  • NODE_ENV controls boot posture.
  • BETTER_AUTH_SECRET is the common auth-layer secret the starter also accepts in place of KOVO_CSRF_SECRET.

Handle failure#

There are three common failure classes:

  • Your app env schema rejects a missing or malformed app-owned variable.
  • Production boot rejects a weak framework signing secret.
  • The runtime and admin/system URLs resolve to different databases, clusters, or primary instances.

When that happens, fix the source env or the app wiring. Do not paper over it by catching the boot error and continuing anyway.

Next#

Spec & diagnostics

Boot validation and CreateAppBootError: packages/server/src/env.ts and packages/server/src/app.ts. DB/runtime env resolution: packages/server/src/postgres-runtime.ts, packages/cli/src/commands/db.ts, and packages/create-kovo/src/index.ts. Build preset override and paranoid mode: packages/cli/src/commands/build-export.ts and packages/server/src/vite.ts. CSP report endpoint: packages/server/src/csp.ts. The main boot refusal path surfaces through CreateAppBootError; the database posture family is the same KV433 set surfaced by kovo db check.

API reference: @kovojs/server.