---
title: "CLI reference"
description: "Every verbatra subcommand and the global flags they share, plus how the CLI reads your environment and loads .env files."
type: "reference"
---
# CLI reference

Every verbatra subcommand and the global flags they share, plus how the CLI reads your environment and loads .env files.

`@verbatra/cli` ships the `verbatra` binary, a thin wrapper over [`@verbatra/sdk`](https://verbatra.kreitz-webdev.de/docs/sdk.md).

## Commands [#commands]

These commands do the work:

<Cards>
  <Card title="init" href="https://verbatra.kreitz-webdev.de/docs/cli/init.md">Create a verbatra config and `.env.example` for this project.</Card>
  <Card title="extract" href="https://verbatra.kreitz-webdev.de/docs/cli/extract.md">Scan your application source for translation call sites and add the new keys to the source locale file.</Card>
  <Card title="translate" href="https://verbatra.kreitz-webdev.de/docs/cli/translate.md">Translate every target locale once, then exit.</Card>
  <Card title="watch" href="https://verbatra.kreitz-webdev.de/docs/cli/watch.md">Re-translate on every source change until interrupted.</Card>
  <Card title="check" href="https://verbatra.kreitz-webdev.de/docs/cli/check.md">Report which keys are missing or stale per locale, read-only.</Card>
  <Card title="diff" href="https://verbatra.kreitz-webdev.de/docs/cli/diff.md">List the exact keys that would be added, re-translated, or are orphaned per locale, read-only.</Card>
  <Card title="report" href="https://verbatra.kreitz-webdev.de/docs/cli/report.md">Print a read-only report: `report provenance` lists which translations a machine wrote and which a person reviewed.</Card>
  <Card title="doctor" href="https://verbatra.kreitz-webdev.de/docs/cli/doctor.md">Validate the project setup and report every problem at once, without calling a provider.</Card>
  <Card title="pseudo" href="https://verbatra.kreitz-webdev.de/docs/cli/pseudo.md">Generate a pseudolocale from the source strings, without calling a provider.</Card>
  <Card title="types" href="https://verbatra.kreitz-webdev.de/docs/cli/types.md">Generate TypeScript declarations for your catalog keys and their message arguments, without calling a provider.</Card>
  <Card title="export" href="https://verbatra.kreitz-webdev.de/docs/cli/export.md">Export untranslated strings for a human translator, as an Excel workbook, one CSV or TSV file per locale, or one XLIFF file per locale for a CAT tool.</Card>
  <Card title="import" href="https://verbatra.kreitz-webdev.de/docs/cli/import.md">Import a filled workbook or delimited file back into the locale files.</Card>
  <Card title="tmx" href="https://verbatra.kreitz-webdev.de/docs/cli/tmx.md">Import a TMX translation memory from another tool into this project's memory, or export this project's memory as a TMX file.</Card>
  <Card title="studio" href="https://verbatra.kreitz-webdev.de/docs/cli/studio.md">Start Verbatra Studio, the local translation dashboard.</Card>
  <Card title="mcp" href="https://verbatra.kreitz-webdev.de/docs/cli/mcp.md">Start a stdio MCP server exposing verbatra's tools to an MCP client.</Card>
</Cards>

## Install and invoke [#install-and-invoke]

Install `@verbatra/cli` as a dev dependency:

```bash
npm install --save-dev @verbatra/cli
```

Then run the binary through your package manager:

```bash
npx @verbatra/cli <command>
```

You need Node.js `^22.22.0 || >=24` (CLI 0.12.x accepts `^22.18.0 || >=24`).

Trying a command before installing? `npx @verbatra/cli <command>` (npm) or `pnpm dlx @verbatra/cli <command>` (pnpm) both work without a prior local install. Always use the scoped name: the unscoped name `verbatra` on npm does not belong to this project.

## Global flags [#global-flags]

These flags mean the same on every command that takes them, so the command pages list only their own flags. The last column names the commands that do not take a flag.

| Flag | Argument | Default | Effect | Not accepted by |
| --- | --- | --- | --- | --- |
| `--cwd` | `<path>` | current directory | start the config search here and resolve the paths you pass against it; locale files resolve against the directory of the config the search found; `init` writes its files there | none |
| `--config` | `<path>` | search for one | load this config file instead of searching; see the [search order](https://verbatra.kreitz-webdev.de/docs/config-file.md) | `init` |
| `--json` | none | off | print a machine-readable [envelope](https://verbatra.kreitz-webdev.de/docs/cli/output.md#json-output) on stdout, one line per record; errors still go to stderr | `mcp`, `studio` |
| `-q`, `--quiet` | none | off | print only results, warnings and errors: no progress, hints or informational lines; works before or after the command name | none |
| `--no-color` | none | color on a terminal | never color the output; see [Terminal output](https://verbatra.kreitz-webdev.de/docs/cli/output.md#terminal-output) | none |
| `-h`, `--help` | none | off | print the help of the program or the command and exit `0` | none |
| `-V`, `--version` | none | off | print the CLI version and exit `0` | none |

An unknown command or flag exits `2`, and so does a bare `verbatra` with no command: it prints the help to stderr and, when no config is found, suggests `verbatra init`. `mcp` never writes to stdout, since stdout is its protocol channel, so it refuses `--json` with `USAGE_ERROR`. From 0.12.0 a `--cwd` that names no existing directory exits `2` with [`INVALID_OPTION`](https://verbatra.kreitz-webdev.de/docs/error-codes.md#invalid_option) on every command, before anything is read or written.

## Environment files [#environment-files]

`translate`, `watch`, `doctor`, `studio`, and `mcp` load `.env.local` and then `.env` from the working directory before they run. When the config the search found sits in a parent directory, they then load the same two files from that directory too; with `--config` they read only the working directory. When an MCP client changes its roots, the MCP server loads both files from the new project root too. `doctor --literals` is the exception: it reads no API key, so it loads neither file. A variable already set in your real environment always wins, then the working directory's files, then the config directory's, and a value in `.env.local` wins over the same variable in `.env`. API keys are read only from the environment, never from the config file or a flag: see [Providers](https://verbatra.kreitz-webdev.de/docs/providers.md). The read-only commands (`check`, `diff`, `report`), the handoff commands (`export`, `import`), `extract`, `init`, `pseudo`, `types`, and `tmx` never call a provider and load no `.env` files.

## .gitignore entries [#gitignore-entries]

A real run of `translate`, `watch`, `import`, `tmx import` or `pseudo` also appends whichever of `.env`, `.env.local`, `.verbatra-local/` and `verbatra.cache.json` an existing `.gitignore` in the project root is missing, and names them on stderr (`--json` and `--quiet` drop that line). This happens as soon as the config has loaded, so a run that then fails has already done it. A dry run leaves the file alone, and none of these commands creates one; [`verbatra init`](https://verbatra.kreitz-webdev.de/docs/cli/init.md) does. A `.gitignore` that is a symbolic link leaving the project is left unchanged, with a warning that `--json` and `--quiet` keep.

## Terminal output [#terminal-output]

Color, the spinner, `--quiet` and the variables that control them are described in [Terminal output](https://verbatra.kreitz-webdev.de/docs/cli/output.md#terminal-output).

## Exit codes [#exit-codes]

The exit-code contract and its edge cases are on [Exit codes and JSON output](https://verbatra.kreitz-webdev.de/docs/cli/output.md#exit-codes). Each command page lists only the codes that command returns.
