---
title: Environment contracts
description: Use defineEnv and env builders to declare typed environment variables, defaults, required values, and secrets.
sidebar:
  icon: key-round
---

An environment contract turns process values, such as a log level or database URL, into validated application settings. Every process value starts as text; the contract parses it, applies intentional defaults, identifies
secrets, and controls the values available through `context.env`.

[defineEnv](/docs/api/config#defineenv) declares these settings in `src/platform/env.ts`.
The [env builders](/docs/api/config#env) describe each field. Pass the declaration to
[defineApp](/docs/api/app#defineapp) in `relkit.config.ts` to make it part of your application.
Declaring the contract does not read environment values; RELKIT resolves them when starting the runtime.

## Declare values with defineEnv [#define-application-values]

```ts title="templates/default/v1/api/src/platform/env.ts"
import { defineEnv, env } from "@relkit/app/config";

export default defineEnv({
  LOG_LEVEL: env.literal("trace", "debug", "info", "warn", "error").default("info"),
});
```

Builders such as `env.string()`, `env.url()`, `env.boolean()`, numeric variants, and `env.literal(...)` define
the accepted runtime value. Defaults are useful for harmless local policy such as log level. Credentials and
other required production values should fail clearly when absent instead of receiving placeholder defaults.

`env.secret()` marks a value as sensitive so generated output, diagnostics, telemetry, and Inspector payloads
can redact it. Secret marking is a safety boundary, not permission to log the value.

## Separate environment from binding references

The contract passed as `defineApp({ env })` resolves values available to application handlers. Integration
configuration also uses named binding references such as `binding.string(...)` and `binding.secret(...)`.
Those references describe runtime wiring for an adapter; they are not additional `context.env` fields unless
the application environment contract declares them too.

Use source-controlled configuration for stable topology and policy. Use environment values for machine-, stack-,
or secret-specific data. Never place resolved credentials in source, graphs, manifests, deployment plans, or
test snapshots.

## Inspect configuration safely

```sh title="Terminal — relkit-orders"
bun run relkit env check
bun run relkit env list
bun run relkit env explain LOG_LEVEL
bun run relkit env example
```

`check` validates the active values, `list` reports value status without printing secret contents, `explain`
describes one declaration, and `example` renders a safe template. Run `bun run check` after changing the contract
so generated types and graph metadata stay current.

Generated commands run under Bun, which loads its normal dotenv files for the process.
For one-shot and production commands, an existing process environment value takes precedence. `.env.example` is an informational
template; RELKIT does not load it as runtime configuration. Keep its placeholder values
separate from real credentials. Moving services leaves the root dotenv files in place.

During `bun dev`, RELKIT reloads active dotenv files for each candidate, including after a
failed reload. Keys declared in those files are managed by the files: additions and edits
replace startup values, and deleting a key removes its previous file-managed value. Other
inherited environment values and explicit RELKIT runtime settings remain in effect.

The startup `NODE_ENV` selects `.env.development`, `.env.production`, or `.env.test`, with
development as the fallback for an absent or custom value. `.env.local` has higher precedence
and is excluded in test mode. `.env.<mode>.local` has the highest file precedence.
Creating, deleting, or atomically replacing an active dotenv file also triggers a reload.
A rejected candidate leaves the previous valid version serving until the repair succeeds;
neither ordinary nor prepared startup requires restarting the CLI after a dotenv repair.

The CLI's `--environment` selects the command's provider environment. It does not turn a
custom application field named `RELKIT_ENV` into business configuration. RELKIT owns that
reserved runtime selector; the application contract continues to describe its own values.

> **Framework-owned variables**
>
> `PORT` and `RELKIT_ENV` are reserved. Configure the listener through `server.port` and select a
> provider environment with the CLI's `--environment` option. Do not declare either name as a custom
> environment field.

{/* Generated by apps/docs/scripts/generate.ts. Do not edit. */}

**Reference and source**

- [`@relkit/config` API](/docs/api/config)

- [`templates/default/v1/api/src/platform/env.ts`](https://github.com/rel-kit/relkit/blob/main/templates/default/v1/api/src/platform/env.ts)
