---
title: Envlock CLI
description: Complete reference for the envlock command-line tool, including all commands, flags, output formats, and exit codes.
url: https://pr-1-ff84656b4b8a.thally.app/envlock/cli
---

# Envlock CLI

Complete reference for the envlock command-line tool, including all commands, flags, output formats, and exit codes.

The `envlock` CLI validates environment variables against a typed contract,
generates `.env.example` files, detects drift, and inspects schemas. Install it
as a dev dependency:

```sh
npm install -D @envlock/cli
```

This provides the `envlock` binary.

## Commands

### envlock check

Validates environment variables against the contract.

```sh
envlock check [--schema <path>] [--env-file <path>] [--merge-process-env] [--strict] [--json]
```

| Flag | Description |
|---|---|
| `--schema <path>` | Path to the config file. Defaults to auto-discovery in the current directory. |
| `--env-file <path>` | Validate this dotenv file instead of `process.env`. |
| `--merge-process-env` | With `--env-file`: layer the file over `process.env` (file values win). |
| `--strict` | With `--env-file`: also report undeclared variables. Ignored without `--env-file` (a note is printed to stderr). |
| `--json` | Print machine-readable JSON output. |
| `--help` | Show command help. |

**Note on `--strict`**: when used without `--env-file`, the flag is ignored and
a message is printed to stderr: `--strict is ignored without --env-file (process.env always carries undeclared variables)`.

**Text output on success**:

```
ok: process.env satisfies N declared variable(s)
```

Or, when validating a file:

```
ok: <source> satisfies N declared variable(s)
```

**Text output on failure**:

```
error: N issue(s) in <source>
```

Followed by a table with columns KEY, CODE, and MESSAGE. Invalid issues with a
received value include `(received "value")` in the message column. Secret values
appear as `"••••••"`.

**JSON output** (with `--json`):

```json
{ "ok": true, "issues": [], "source": "process.env" }
```

Or on failure:

```json
{
  "ok": false,
  "issues": [
    { "key": "PORT", "code": "invalid", "message": "expected a port number between 1 and 65535", "received": "abc" }
  ],
  "source": ".env"
}
```

### envlock example

Renders a `.env.example` file from the contract.

```sh
envlock example [--schema <path>] [--out <path>] [--check]
```

| Flag | Description |
|---|---|
| `--schema <path>` | Path to the config file. |
| `--out <path>` | Write the rendered example to this file path. |
| `--check` | Check whether the example file is up to date (exit 1 if not). |
| `--help` | Show command help. |

Three modes of operation:

1. **No flags**: renders the example to stdout, exits 0.
2. **`--out <path>`**: writes the file, prints `ok: wrote <path> (N variable(s))`, exits 0.
3. **`--check`**: compares rendered output against the file at `--out` (or `.env.example` by default).
   - Match: `ok: <path> is up to date` (exit 0).
   - File missing: ``error: <path> does not exist; run `envlock example --out <path>` `` (exit 1).
   - File differs: ``error: <path> is out of date; run `envlock example --out <path>` `` (exit 1).

### envlock diff

Compares a dotenv file against the contract. Always runs in strict mode.

```sh
envlock diff [--schema <path>] [--env-file <path>] [--json]
```

| Flag | Description |
|---|---|
| `--schema <path>` | Path to the config file. |
| `--env-file <path>` | Dotenv file to compare. Defaults to `.env`. |
| `--json` | Print machine-readable JSON output. |
| `--help` | Show command help. |

**Text output on success**:

```
ok: <path> matches the contract exactly
```

**Text output on failure**:

```
error: <path> drifts from the contract
```

Followed by up to three sections: `Missing (N):`, `Unknown (N):`, and
`Invalid (N):`.

**JSON output** (with `--json`):

```json
{ "missing": [], "unknown": [], "invalid": [], "ok": true, "source": ".env" }
```

### envlock inspect

Displays the schema as a human-readable table or JSON.

```sh
envlock inspect [--schema <path>] [--json]
```

| Flag | Description |
|---|---|
| `--schema <path>` | Path to the config file. |
| `--json` | Print the `describeSchema()` result as a JSON array. |
| `--help` | Show command help. |

**Text output**: a header line `Contract: <path> (N variable(s))` followed by a
table with columns KEY, TYPE, REQUIRED, DEFAULT, SECRET, and DESCRIPTION.

### envlock init

Writes a starter `envlock.config.mjs` file in the current directory.

```sh
envlock init
```

| Flag | Description |
|---|---|
| `--help` | Show command help. |

If `envlock.config.mjs` or `envlock.config.js` already exists, the command
prints an error and exits 1:

```
error: <name> already exists; delete it first if you want a fresh starter
```

Otherwise it writes `envlock.config.mjs` with a starter config and prints:

```
ok: wrote envlock.config.mjs; edit it, then run `envlock check`
```

The starter config declares four example variables (`NODE_ENV`, `PORT`,
`DATABASE_URL`, `LOG_LEVEL`) as a starting point for your contract.

### help and version

```sh
envlock help          # show global help (exit 0)
envlock --help        # same
envlock -h            # same
envlock --version     # print version string (exit 0)
envlock -v            # same
```

Running bare `envlock` with no arguments exits with code 2.

## Exit codes

| Code | Meaning |
|---|---|
| 0 | Validation passed, no drift, or operation completed successfully. |
| 1 | Validation failed, drift detected, or `init` found an existing config file. |
| 2 | Usage error: unknown command, unknown flag, missing flag value, unexpected argument. |
| 3 | Configuration or file error: config not found, import failed, no schema export, env file unreadable. |

## Config discovery

The CLI looks for a config file in the current working directory by probing
these candidates in order:

1. `envlock.config.mjs`
2. `envlock.config.js`

The first file that exists is used. The `--schema <path>` flag overrides
discovery entirely, accepting an absolute path or a path relative to the current
directory.

Config files are loaded via dynamic `import()` and must be valid ESM JavaScript
(`.mjs` or `.js`, not `.ts`).

### Config file format

The config file must export a schema created with `defineEnv`. Two export styles
are accepted:

**Default export** (recommended):

```js
import { defineEnv, env } from "@envlock/core";

export default defineEnv({
  PORT: env.port().default(3000),
  DATABASE_URL: env.url().secret(),
});
```

**Named export**:

```js
import { defineEnv, env } from "@envlock/core";

export const schema = defineEnv({
  PORT: env.port().default(3000),
  DATABASE_URL: env.url().secret(),
});
```

## Error messages

### Usage errors (exit 2)

These errors indicate incorrect invocation of the CLI:

- `unknown command "<name>"`
- `unknown flag --<name>`
- `flag --<name> does not take a value`
- `flag --<name> requires a value`
- `unexpected argument "<arg>"`

### Configuration errors (exit 3)

These errors indicate problems loading the schema or env file:

- `schema file not found: <path>`
- ``no envlock.config.mjs or envlock.config.js found in <cwd> (pass --schema <path> or run `envlock init`)``
- `failed to import <path>: <detail>`
- ``<path> must `export default defineEnv({...})` (or export a named `schema`)``
- `could not read env file <path>: <detail>`