# comvi pull

Download translations from your Comvi project to local JSON files, filtered by locale or namespace, for builds and offline development.

Canonical: https://comvi.io/docs/cli/pull

Download every locale and namespace of the project to the configured `translationsPath` as
flat JSON files.

## Usage

`Terminal`

```bash
comvi pull [options]
```

## Options

| Option | Default | Meaning |
| --- | --- | --- |
| `-c, --config <path>` | nearest `.comvirc.json` | Config file to read |
| `-l, --locale <locales>` | `locales` in config, else all | Comma-separated BCP-47 codes to download (`en,pt-BR`). A code the project does not have exits `4` |
| `-n, --ns <namespaces>` | `namespaces` in config, else all | Comma-separated namespaces to download. A namespace the project does not have exits `4` |
| `-p, --path <path>` | `translationsPath` in config | Output directory |
| `--empty-dir` | `pull.emptyDir` in config, else off | Remove the pulled locales and namespaces after the fetch succeeds, then write |
| `--dry-run` | off | List the files a pull would write, and with `--empty-dir` the files it would remove, without touching the filesystem |

A flag replaces the config value for that run; the two lists never merge.

## Output layout

`src/locales/`

```text
src/locales/
├── en.json            # default namespace
├── de.json
├── common/
│   ├── en.json
│   └── de.json
└── auth/
    ├── en.json
    └── de.json
```

`src/locales/common/en.json`

```json
{
"greeting": "Hello, {name}!",
"nav.home": "Home",
"nav.settings": "Settings"
}
```

With the default `fileTemplate` of `{namespace}/{languageTag}.json`, the namespace marked
default in the project is written at the root as `{languageTag}.json` and every other
namespace gets a directory. A custom template such as `{languageTag}/{namespace}.json` is
matched literally and turns that root special case off. Files are always flat: a key
named `nav.home` is one property, never a nested `nav` object.

## Examples

`Pull two locales of one namespace`

```bash
comvi pull --locale en,de --ns common
```

`.github/workflows/build.yml`

```yaml
- run: npx comvi pull
env:
    COMVI_API_KEY: ${{ secrets.COMVI_API_KEY }}
- run: npx comvi typegen
- run: npm run build
```

`package.json`

```json
{
"scripts": {
    "predev": "comvi pull && comvi typegen"
}
}
```

Pulling in CI keeps translation files out of the repository and puts the latest published
values in every build. In a monorepo, run the command from the package that owns the
`.comvirc.json`, or pass `--config ../../.comvirc.json`.

## Clear stale files

`Terminal`

```bash
comvi pull --empty-dir --dry-run
comvi pull --empty-dir
```

`--empty-dir` removes files that were deleted on the platform. The clear runs after the
fetch and only once every requested locale and namespace came back, so a network failure, a
rejected key or a typo in a filter leaves the working copy as it was. The clear follows the
filters: `--ns common --empty-dir` removes the `common` files and nothing else, and a
`locales` or `namespaces` list in the config scopes it the same way. Emptied directories
are removed with their files. A `translationsPath` at or above the working directory is
refused before anything is deleted.

> **caution**
>
> With no locale and no namespace filter, from flags or from the config, `--empty-dir` removes
> everything under `translationsPath`, including files that are not translation files.

## Exit codes

| Code | Meaning |
| --- | --- |
| `0` | Files written, or a dry run finished |
| `1` | Missing `.comvirc.json`, auth failure, network error |
| `4` | Invalid config, a locale or namespace the project does not have, or a `--dotenv` file that does not exist |

## Next steps

- [comvi push](/docs/cli/push): upload local files back to the project.
- [comvi typegen](/docs/cli/typegen): generate types after a pull.
- [Load translations on demand](/docs/i18n/loading-translations): how the SDK loads the files a pull wrote.
- [CI/CD integration](/docs/platform/recipes/ci-cd-integration): full pipeline examples.
