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.
You don’t have to write the release section by hand. chamoji setup writes
it from what it finds in the repo.
The file
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
repositoryUrl- Type
- string
- Description
The repo’s URL, for commit, issue (
#12) and compare links. Default: theoriginremote.
- Name
groups- Type
- list of groups
- Description
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.
- Name
release- Type
- object
- Since
- SINCE 0.13.0
- Description
How releases are versioned and tagged. Default: one package, one
v*tag and oneCHANGELOG.md. See The release section.
A group
- Name
group- Type
- string · required
- Description
The section’s key, such as
added. Commits that match no group go tomiscwhen that group exists.
- Name
label- Type
- string · required
- Description
The heading in the changelog, such as
Added.
- Name
emojis- Type
- list of strings · required
- Description
Gitmoji codes, such as
sparklesfor ✨. Colons are dropped, so:sparkles:works too. Conventional types and plain messages land here through the gitmoji they map to.
- Name
hidden- Type
- boolean
- Description
Match these commits, then leave them out of the output. Default: false.
- Name
collapse- Type
- boolean
- Description
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
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.
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/*"]
}
}
A library monorepo
{
"release": {
"schema": 1,
"shape": "libraries",
"units": {
"core": {"path": "packages/core"},
"cli": {"path": "packages/cli"},
"ui": {"path": "packages/ui"}
},
"fixed": [["core", "cli"]]
}
}
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
schema- Type
- 1 · required
- Since
- SINCE 0.13.0
- Description
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.
- Name
shape- Type
- 'single' | 'apps' | 'libraries' · required
- Since
- SINCE 0.13.0
- Description
appsversions each app,librarieseach package.singleis the default behaviour, one release for the whole repo, and takes no other key.
- Name
units- Type
- object
- Since
- SINCE 0.13.0
- Description
Each unit by name, with its settings (below). A name can’t be empty or contain
/or spaces. Default: none.
- Name
exclude- Type
- list of path globs
- Since
- SINCE 0.13.0
- Description
Paths that belong to no unit. Commits that change only these are left out. Default: none.
- Name
sharedChanges- Type
- 'ride-along' | 'release-dependents'
- Since
- SINCE 0.13.0
- Description
What a commit to an internal package does.
ride-alongreleases nothing on its own, and goes in each unit’s next release, marked “viapackages/…”.release-dependentsreleases every unit that uses the package, by at least a patch. Default:ride-alongfor apps,release-dependentsfor libraries.
- Name
rootFiles- Type
- 'none' | 'all' | 'note'
- Since
- SINCE 0.13.0
- Description
What a commit that changes only files outside every package, such as the lockfile or CI, does.
noneleaves it out,allcounts it for every unit, andnoteadds a line such as “Tooling and CI: 12 changes” to each unit’s notes. Default:none.
- Name
zeroMajor- Type
- 'minor'
- Since
- SINCE 0.13.0
- Description
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.
- Name
fixed- Type
- list of lists of unit names
- Since
- SINCE 0.13.0
- Description
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.
- Name
upstream- Type
- object
- Since
- SINCE 0.13.0
- Description
The history of a template you started from, so it stays out of your notes. See upstream. Default: unset.
- Name
tags- Type
- object
- Since
- SINCE 0.13.0
- Description
ignoreandaliases, for tags that aren’t releases or don’t parse. See tags. Default: none of either.
- Name
rootChangelog- Type
- boolean
- Since
- SINCE 0.13.0
- Description
Add a root
CHANGELOG.mdthat lists every release, with links to the units’ changelogs. Default: false.
- Name
githubReleases- Type
- 'per-unit' | 'combined'
- Since
- SINCE 0.13.0
- Description
One GitHub release per unit, or one per release commit. Default:
per-unit.
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
path- Type
- string · required
- Description
The unit’s folder, from the repo root, such as
apps/web. Paths match on whole folder names, soapps/webdoesn’t matchapps/web-admin.
- Name
tag- Type
- template
- Description
The tag for a release.
{unit}is the unit’s name inunits,{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 onefixedgroup.
- Name
read- Type
- list of templates
- Description
Older formats, such as
web-v{version}, to read past releases from. Default: none.
- Name
versioning- Type
- 'semver' | 'calver'
- Description
calvergives date versions: the year, the month and a count of the unit’s releases that month, such as2026.11.0, with no zero padding. Default:semver.
- Name
firstVersion- Type
- string
- Description
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
calverunit.
- Name
versionFiles- Type
- list of paths
- Description
Other files that carry the version, such as
apps/mobile/app.config.ts, anInfo.plistor anandroid/app/build.gradle. The unit’spackage.jsonis 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.
- Name
buildNumber- Type
- 'untouched' | 'increment'
- Description
incrementraisesCFBundleVersion,versionCodeand Expo’sios.buildNumberandandroid.versionCodeby one. It does nothing when the app uses EAS remote versioning. Default:untouched.
- Name
changelog- Type
- path
- Description
Where the unit’s changelog goes, from the repo root. Default:
CHANGELOG.mdin the unit’s folder.
upstream
For a repo that began as a clone of a template you started from, and keeps pulling from it.
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
name- Type
- string · required
- Description
The template’s name, for the sync lines in your notes.
- Name
remote- Type
- string
- Description
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.
- Name
since- Type
- commit or ref
- Description
Your first commit that isn’t the template’s. Default: unset.
- Name
authors- Type
- list of emails
- Since
- SINCE 0.14.0
- Description
Commits on HEAD by these authors, compared ignoring case, are the template’s. 0.13.0 accepts the key and ignores it. Default: none.
tags
release.tags
"tags": {
"aliases": {"final-release": {"unit": "web", "version": "1.0.0"}},
"ignore": ["^\\d+\\.\\d+\\.\\d+$", "^wip/"]
}
- Name
ignore- Type
- list of regular expressions
- Description
Tags that aren’t releases, such as ones that came with a template. These are regular expressions, not globs:
^wip/matches tags that start withwip/. Default: none.
- Name
aliases- Type
- object
- Description
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.jsonor thegitmojikey inpackage.json:emojiFormat(emojiorcode; defaultemoji), andscopePrompt,messagePrompt,capitalizeTitleandautoAdd(default true, true, true and false). - Suggestions from Jev are opt-ins in git config,
chamoji.composerandchamoji.sendDiffs, so a repo you clone can’t switch them on for you.