# Config

> Every key in chamoji.config.json, including the release section, with its default.

Source: https://www.chamoji.dev/docs/reference/config

chamoji reads `chamoji.config.json` in the folder you run it from, when there is one, so run chamoji from the repo root. Every key is optional: with no file, you get the default sections, links from `origin`, and one version for the whole repo.

[CONFIG]

> **Note:** You don’t have to write the `release` section by hand. `chamoji setup` writes
> it from what it finds in the repo.

## The file

```json title="chamoji.config.json"
{
	"repositoryUrl": "https://github.com/acme/widgets",
	"groups": [
		{"group": "added", "label": "Added", "emojis": ["sparkles", "tada"]},
		{"group": "fixed", "label": "Fixed", "emojis": ["bug", "ambulance"]},
		{
			"group": "useless",
			"label": "Useless",
			"emojis": ["bookmark"],
			"hidden": true
		},
		{"group": "misc", "label": "Miscellaneous", "emojis": []}
	]
}
```

`--config <file>` reads another file instead. A file that doesn’t parse, or a key with the wrong type, stops the command with a message that names the key.

## Top-level keys

| Name | Type | Description |
| --- | --- | --- |
| `repositoryUrl` | string | The repo’s URL, for commit, issue (`#12`) and compare links. Default: the `origin` remote. |
| `groups` | list of groups | The changelog’s sections, in order. It replaces the default sections; it doesn’t add to them. Default: the sections below. A plain JSON array of groups, the older format of this file, is also accepted. |
| `release` | object | How releases are versioned and tagged. Default: one package, one `v*` tag and one `CHANGELOG.md`. See [The release section](#the-release-section). (since 0.13.0) |

## A group

| Name | Type | Description |
| --- | --- | --- |
| `group` | string · required | The section’s key, such as `added`. Commits that match no group go to `misc` when that group exists. |
| `label` | string · required | The heading in the changelog, such as `Added`. |
| `emojis` | list of strings · required | Gitmoji codes, such as `sparkles` for ✨. Colons are dropped, so `:sparkles:` works too. Conventional types and plain messages land here through the gitmoji they map to. |
| `hidden` | boolean | Match these commits, then leave them out of the output. Default: false. |
| `collapse` | boolean | Render the group as one summary line, as the default Dependencies group does. Default: false. |

### The default sections

| `group` | `label` | Notes |
| --- | --- | --- |
| `added` | Added | ✨ 🎉 and other additions |
| `changed` | Changed | ♻️ ⚡️ 🎨 ⏪ and other changes |
| `breaking_changes` | Breaking changes | 💥, and every commit marked breaking |
| `deprecated` | Deprecated | 🗑️ |
| `removed` | Removed | 🔥 🔇 ⚰️ |
| `fixed` | Fixed | 🐛 🚑️ 🩹 |
| `security` | Security | 🔒️ 🔐 🛂 |
| `documentation` | Documentation | 📝 ✏️ |
| `maintenance` | Maintenance | 👷 💚 ✅ 🧪 |
| `dependencies` | Dependencies | ⬆️ ⬇️ 📌 ➕ ➖, collapsed into one line |
| `useless` | Useless | 🔖 🔀, hidden |
| `misc` | Miscellaneous | 💡 🚀 🚧 and anything no other group claims |

Every official gitmoji is in exactly one of them.

## The release section

MONOREPOS · release

Without a `release` section, the repo is one package: one version, one `v*` tag and one `CHANGELOG.md`. That is also right for a monorepo whose packages ship together. With one, every unit (an app or a package) gets its own version, tag, changelog and GitHub release.

```json title="An app monorepo"
{
	"release": {
		"schema": 1,
		"shape": "apps",
		"units": {
			"web": {"path": "apps/web", "tag": "web/v{version}"},
			"mobile": {
				"path": "apps/mobile",
				"tag": "mobile/v{version}",
				"versionFiles": ["apps/mobile/app.config.ts"]
			}
		},
		"exclude": ["apps/e2e", "apps/dev-tool", "tooling/*"]
	}
}
```

```json title="A library monorepo"
{
	"release": {
		"schema": 1,
		"shape": "libraries",
		"units": {
			"core": {"path": "packages/core"},
			"cli": {"path": "packages/cli"},
			"ui": {"path": "packages/ui"}
		},
		"fixed": [["core", "cli"]]
	}
}
```

> **Note:** Pin the CLI to 0.13.0 or newer before you add a `release` section. 0.12.1
> refuses it, and 0.12.0 ignores it and cuts one release for the whole repo.

| Name | Type | Description |
| --- | --- | --- |
| `schema` | 1 · required | The section’s format. A higher number is from a newer chamoji, which stops with “this repo’s release settings need chamoji 0.13.0 or newer” and exit code 2. (since 0.13.0) |
| `shape` | 'single' \| 'apps' \| 'libraries' · required | `apps` versions each app, `libraries` each package. `single` is the default behaviour, one release for the whole repo, and takes no other key. (since 0.13.0) |
| `units` | object | Each unit by name, with its settings (below). A name can’t be empty or contain `/` or spaces. Default: none. (since 0.13.0) |
| `exclude` | list of path globs | Paths that belong to no unit. Commits that change only these are left out. Default: none. (since 0.13.0) |
| `sharedChanges` | 'ride-along' \| 'release-dependents' | What a commit to an internal package does. `ride-along` releases nothing on its own, and goes in each unit’s next release, marked “via `packages/…`”. `release-dependents` releases every unit that uses the package, by at least a patch. Default: `ride-along` for apps, `release-dependents` for libraries. (since 0.13.0) |
| `rootFiles` | 'none' \| 'all' \| 'note' | What a commit that changes only files outside every package, such as the lockfile or CI, does. `none` leaves it out, `all` counts it for every unit, and `note` adds a line such as “Tooling and CI: 12 changes” to each unit’s notes. Default: `none`. (since 0.13.0) |
| `zeroMajor` | 'minor' | Make a breaking change raise the minor version while a unit is at 0.x. Default: unset, so a breaking change raises the major version. (since 0.13.0) |
| `fixed` | list of lists of unit names | Units that always share one version: the largest bump of any of them. When one releases, they all do. A unit can be in one group only. Default: none. (since 0.13.0) |
| `upstream` | object | The history of a template you started from, so it stays out of your notes. See [upstream](#upstream). Default: unset. (since 0.13.0) |
| `tags` | object | `ignore` and `aliases`, for tags that aren’t releases or don’t parse. See [tags](#tags). Default: none of either. (since 0.13.0) |
| `rootChangelog` | boolean | Add a root `CHANGELOG.md` that lists every release, with links to the units’ changelogs. Default: false. (since 0.13.0) |
| `githubReleases` | 'per-unit' \| 'combined' | One GitHub release per unit, or one per release commit. Default: `per-unit`. (since 0.13.0) |

Every key but `schema` and `shape` needs `apps` or `libraries`. With `single`, any other key stops the command.

## A unit

Each entry in `release.units`, such as `"web": {"path": "apps/web"}`.

| Name | Type | Description |
| --- | --- | --- |
| `path` | string · required | The unit’s folder, from the repo root, such as `apps/web`. Paths match on whole folder names, so `apps/web` doesn’t match `apps/web-admin`. |
| `tag` | template | The tag for a release. `{unit}` is the unit’s name in `units`, `{name}` its package name and `{version}` the version, which the template must contain. Default: `{unit}/v{version}` for apps and `{name}@{version}` for libraries. Two units share a template without `{unit}` or `{name}` only in one `fixed` group. |
| `read` | list of templates | Older formats, such as `web-v{version}`, to read past releases from. Default: none. |
| `versioning` | 'semver' \| 'calver' | `calver` gives date versions: the year, the month and a count of the unit’s releases that month, such as `2026.11.0`, with no zero padding. Default: `semver`. |
| `firstVersion` | string | The version of the unit’s first release, when it has no tag yet. Default: the version in its manifest, or a date version for a `calver` unit. |
| `versionFiles` | list of paths | Other files that carry the version, such as `apps/mobile/app.config.ts`, an `Info.plist` or an `android/app/build.gradle`. The unit’s `package.json` is always bumped. A path outside the repo, or a symlink, is refused, and a listed file where chamoji can’t find the version stops the release before anything changes. Default: none. |
| `buildNumber` | 'untouched' \| 'increment' | `increment` raises `CFBundleVersion`, `versionCode` and Expo’s `ios.buildNumber` and `android.versionCode` by one. It does nothing when the app uses EAS remote versioning. Default: `untouched`. |
| `changelog` | path | Where the unit’s changelog goes, from the repo root. Default: `CHANGELOG.md` in the unit’s folder. |

## upstream

For a repo that began as a clone of a template you started from, and keeps pulling from it.

```json title="release.upstream"
"upstream": {
	"remote": "upstream",
	"name": "Acme Starter",
	"since": "<first commit that is yours>",
	"authors": ["dev@acme-starter.example"]
}
```

The template’s history is every commit that the remote’s fetched branches reach, that a version-like tag in `tags.ignore` reaches, or that one of `authors` wrote. Those commits are left out of every unit’s notes and never release anything. Each merge that brings them in becomes one line, such as “Updated the Acme Starter base to 4.0.2”.

| Name | Type | Description |
| --- | --- | --- |
| `name` | string · required | The template’s name, for the sync lines in your notes. |
| `remote` | string | The template’s remote, which must be fetched. In CI, where the checkout has only `origin`, add and fetch it before chamoji runs. Default: unset. |
| `since` | commit or ref | Your first commit that isn’t the template’s. Default: unset. |
| `authors` | list of emails | Commits on HEAD by these authors, compared ignoring case, are the template’s. 0.13.0 accepts the key and ignores it. Default: none. (since 0.14.0) |

## tags

```json title="release.tags"
"tags": {
	"aliases": {"final-release": {"unit": "web", "version": "1.0.0"}},
	"ignore": ["^\\d+\\.\\d+\\.\\d+$", "^wip/"]
}
```

| Name | Type | Description |
| --- | --- | --- |
| `ignore` | list of regular expressions | Tags that aren’t releases, such as ones that came with a template. These are regular expressions, not globs: `^wip/` matches tags that start with `wip/`. Default: none. |
| `aliases` | object | A version for a tag that doesn’t parse but is a real release, as `{unit, version}`. With one unit, the value can be the version string alone. Default: none. |

chamoji never moves, deletes or renames a tag. Tags that match nothing stay in git, untouched.

## Settings kept elsewhere

Two things aren’t in `chamoji.config.json`:

- **The commit composer** reads gitmoji-cli’s settings, from `.gitmojirc.json` or the `gitmoji` key in `package.json`: `emojiFormat` (`emoji` or `code`; default `emoji`), and `scopePrompt`, `messagePrompt`, `capitalizeTitle` and `autoAdd` (default true, true, true and false).
- **Suggestions from Jev** are opt-ins in git config, `chamoji.composer` and `chamoji.sendDiffs`, so a repo you clone can’t switch them on for you.

## Related

- [Set up a repo](https://www.chamoji.dev/docs/set-up-a-repo.md): Let chamoji setup write the release section for you.
- [Monorepos](https://www.chamoji.dev/docs/guides/monorepos.md): Which commits belong to which unit, and how shared changes ride along.
- [How commits are read](https://www.chamoji.dev/docs/reference/how-commits-are-read.md): How a commit finds its section.
