# How dev and publish work

The manifest declares where Crowdin loads the app's bundle from: `bundle.mode` is either `internal` (Crowdin serves the bundle you uploaded) or `external` (Crowdin loads it from a URL).

The two CLI commands pivot the app between these modes:

- [`dev`](/serverless-apps/reference/cli-commands/#dev) offers to point your app at `http://localhost:<port>/`, so everything you edit shows up inside Crowdin instantly, hot module replacement included.
- [`publish`](/serverless-apps/reference/cli-commands/#publish) uploads `dist/bundle.zip` and offers to switch the app back to the Crowdin-served bundle.

Both update the app in Crowdin *and* your local `manifest.json` - a changed `manifest.json` after `dev` is expected. Pass `--yes` to apply without prompts (e.g. in scripts) or `--no-manifest-sync` to leave the bundle mode untouched.

## The bundle contract

The Crowdin host always loads `<bundle-url>/app.js`. The CLI's build produces exactly that: a single `dist/app.js` (an IIFE bundle with CSS injected by JS), plus runtime assets such as translation catalogs under `dist/locales/`. During `dev`, the same contract is preserved - the dev server serves a generated `app.js` that enables hot module replacement inside the Crowdin iframe.

## Who can see the app

Publishing changes where the bundle is served from - it does not widen the audience. The app is registered and installed in your account when `create` runs and stays private to it until you [submit it to the Crowdin Store](https://support.crowdin.com/developer/crowdin-apps-publishing/) - serverless apps can be listed on the store and installed from it like any other Crowdin app.

In each account where the app is installed, who sees it is governed by the manifest's [`default_permissions`](/serverless-apps/reference/manifest/#default_permissions) (defaults: `user: owner`, `project: own`) and by the [installed app's settings](https://support.crowdin.com/developer/crowdin-apps-installation/), where an admin can change the audience later - e.g. open the app to managers or all project members.

To let teammates work on the app itself, share the repository: `.env` (the app link) is not committed, so they run `login` and `link` once - see [the .env file](/serverless-apps/reference/configuration/#the-apps-env-file). To remove an app you no longer need, uninstall it from the apps settings in Crowdin.

## Keeping the manifest in sync

`manifest.json` lives in your repository, and Crowdin stores its own copy for the registered app. Besides the automatic bundle-mode updates, the CLI gives you explicit sync commands:

- `manifest validate` checks the local file against the schema, offline (exits with code 1 when invalid);
- `manifest status` diffs the local file against Crowdin (exits with code 1 on drift);
- `manifest pull` overwrites local fields with Crowdin's values;
- `manifest push` uploads local changes to Crowdin.

See the [manifest reference](/serverless-apps/reference/manifest/) for what the file contains.