Skip to content

comvi push

The comvi push command uploads local translation files to the Comvi platform. Use it to sync translations that developers add in code back to the platform where translators can review and translate them into other languages.

You need a .comvirc.json file in your project root and an API key. Prefer COMVI_API_KEY for the key:

.comvirc.json
{
"apiBaseUrl": "https://api.comvi.io",
"translationsPath": "./src/locales",
"fileTemplate": "{namespace}/{languageTag}.json",
"format": "json"
}
Terminal window
comvi push

This reads all translation files from the configured translationsPath and uploads them to your Comvi project. Conflict handling is controlled by --force-mode.

Terminal window
comvi push [options]
OptionAliasDefaultDescription
--config-c.comvirc.jsonPath to the Comvi config file
--locale-lAll detected localesComma-separated list of locale tags to upload
--ns-nAll detected namespacesComma-separated list of namespaces to upload
--path-p.comvirc.jsontranslationsPathSource directory containing translation files
--dry-runfalsePreview changes without uploading anything
--force-mode.comvirc.jsonpush.forceMode or 'ask'Conflict resolution: override, keep, ask, or abort

The CLI expects files laid out by the configured fileTemplate, matching the structure comvi pull produces. With the default template ({namespace}/{languageTag}.json), the default namespace is stored at the root as {languageTag}.json, and every other namespace gets its own subdirectory:

src/locales/
├── en.json # default namespace (root)
├── de.json
├── fr.json
├── common/
│ ├── en.json
│ ├── de.json
│ └── fr.json
└── auth/
├── en.json
└── de.json

Each JSON file contains flat or nested key-value pairs:

src/locales/common/en.json
{
"greeting": "Hello, {name}!",
"nav.home": "Home",
"nav.settings": "Settings"
}

With the default template the CLI detects the namespace from the directory (root = default namespace) and the language from the filename. A custom fileTemplate is matched literally, so the layout follows whatever placeholders you configure.

Always preview what will change before pushing to the platform. The --dry-run flag prints a summary of how many keys would be created, updated, and how many conflict with existing platform values — without uploading anything. Push never deletes keys, so dry-run never reports deletions:

Terminal window
comvi push --dry-run

Example output:

📦 Push preview (dry run):
✅ Created: 3 keys
📝 Updated: 1 translations
⚠️ Conflicts: 0 keys

When conflicts are detected, the preview also tells you how to resolve them:

📦 Push preview (dry run):
✅ Created: 3 keys
📝 Updated: 1 translations
⚠️ Conflicts: 2 keys
Run with --force-mode override to overwrite remote values.
Run with --force-mode keep to upload only non-conflicting values.

When a key already exists on the platform, --force-mode controls what happens. The default is ask, which prompts interactively in a terminal. Use a non-interactive mode in CI pipelines.

ModeBehaviour
askCount conflicts and prompt for override, keep, or abort (requires a TTY)
overrideLocal values replace existing platform translations
keepExisting platform translations are preserved; only new keys are created
abortStop immediately if any conflict is detected; nothing is written

New keys are always created regardless of mode.

Terminal window
# Preview first, then override
comvi push --dry-run
comvi push --force-mode override
# Push only new keys — never touch existing translator work
comvi push --force-mode keep
# Fail fast if anything would conflict (useful in strict CI)
comvi push --force-mode abort

Upload only certain locales:

Terminal window
# Push only the source language
comvi push --locale en
# Push English and German
comvi push -l en,de

Upload only certain namespaces:

Terminal window
# Push only the common namespace
comvi push --ns common
# Push common and auth namespaces
comvi push -n common,auth

Push translations from your main branch after a merge so that new keys are immediately available to translators:

.github/workflows/push-translations.yml
name: Push Translations
on:
push:
branches: [main]
paths:
- 'src/locales/en/**'
jobs:
push:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm ci
- run: npx comvi push --locale en
env:
COMVI_API_KEY: ${{ secrets.COMVI_API_KEY }}

This workflow triggers only when the source language files change on main, pushing new and updated keys to the platform for translators.

All push options can be set in .comvirc.json:

.comvirc.json
{
"apiBaseUrl": "https://api.comvi.io",
"translationsPath": "./src/locales",
"fileTemplate": "{namespace}/{languageTag}.json",
"format": "json",
"push": {
"forceMode": "ask"
}
}

Command-line flags override config file values.