# Staging to production

Keep staging and production translations in separate projects, point each app at its own CDN endpoint, and promote content on your release cadence.

Canonical: https://comvi.io/docs/platform/recipes/staging-production

A project has exactly one Content Deploy configuration and one CDN endpoint, so separating
environments means separating projects: one for staging, one for production. Content moves
between them when you promote it.

`.env.staging`

```bash
VITE_COMVI_CDN_URL=https://cdn.comvi.io/<staging-token>
```

`.env.production`

```bash
VITE_COMVI_CDN_URL=https://cdn.comvi.io/<production-token>
```

`src/i18n.ts`

```ts
cdnLoader({ cdnUrl: import.meta.env.VITE_COMVI_CDN_URL })
```

The variable name is yours; the loader reads only `cdnUrl`.

## Set up

1. **Create two projects**, for example `checkout` and `checkout-staging`, with the same
   source language. It cannot be changed after creation.

2. **Enable Content Deploy in each** under **Settings → Content Deploy**: pick the locales
   and namespaces and save. Each project gets its own endpoint URL at the top of the page.

3. **Point each app at its own endpoint** through the `VITE_COMVI_CDN_URL` variable.

4. **Do all the work in staging.** Translators write there, reviewers approve there, QA
   looks at the staging app. Staging deploys within a minute of each save.

5. **Promote on your release cadence** with export and import, or with the CLI.

Projects and members are both capped per plan, so two projects may be the whole allowance.
Check the [current limits](https://comvi.io/pricing) first.

## Promote with export and import

1. In staging, open **Export**, select the locales and namespaces, and set the status filter
   to `Translated`.

2. Download the archive, laid out as `<namespace>/<locale>.json`.

3. In production, open **Import** and upload the archive.

4. Resolve conflicts with **Keep existing** or **Use imported**, or apply one policy to
   everything left unresolved.

5. Commit the import. Production's Content Deploy picks the change up on its own debounce.

This path has a status filter, so use it whenever staging still holds work in progress. See
[Import & export](/docs/platform/import-export).

## Promote with the CLI

`Terminal`

```bash
COMVI_API_KEY=$STAGING_KEY npx --package @comvi/cli comvi pull --path ./promote
COMVI_API_KEY=$PROD_KEY npx --package @comvi/cli comvi push --path ./promote --force-mode keep
```

The pull takes every value the staging key can see, whatever its status, and the push writes
all of them into production as `Translated`. Use it only when staging is fully reviewed at
release time. `--force-mode keep` leaves existing production values alone on conflict;
`override` replaces them. [CI/CD integration](/docs/platform/recipes/ci-cd-integration)
wires it to a release tag.

## Trade-offs

A draft in staging cannot reach production, because nothing crosses between two projects on
its own. The cost is two projects to keep in step: languages and namespaces added twice,
members with access to both, and two slots of the plan's project limit. Translation memory
and glossaries are organization-level, so they stay shared.

Use a second organization instead when the environments need different people, not only
different content: an agency that works staging but must never see production, or separate
billing. Translation memory and glossaries then no longer carry over.

## Test a new string

1. A developer adds a key in the staging dashboard or pushes a translation file there.
2. Translators fill it in. Every saved value lands as `Needs Review`.
3. Staging deploys within about a minute, and QA checks the string in the staging app.
4. A reviewer sets the value to `Translated`.
5. The next promotion carries it to production.

A key that shows in production but not in staging usually means the staging project's
Content Deploy locale or namespace selection leaves it out.

## Rollback

There is no rollback. A failed deploy leaves the files it uploaded live next to the ones it
never replaced, and a successful deploy with bad content has replaced the good content.
Recover with a fresh deploy: fix the values in production and wait for auto-deploy or press
**Deploy Now**, or re-import the last known-good export. Exports are your rollback points,
so keep a scheduled `comvi pull` or a regular export archive somewhere durable.

> **Do not share one API key across environments**
>
> Revoking the production key would break staging too. One key per project per job.

## Next steps

- [Content Deploy / CDN](/docs/platform/cdn): Status filters, debounce and failure thresholds.
- [Import & export](/docs/platform/import-export): The promotion path with a status filter.
- [Translator and reviewer workflow](/docs/platform/recipes/translator-review-workflow): How approval happens in staging.
- [CI/CD integration](/docs/platform/recipes/ci-cd-integration): Automate promotion on release.
