Skip to content

Options

The preset takes a config object that customizes which commits are recognized, how they’re grouped, and how links are built. The simplest way to pass it is inline via loadPreset, alongside the preset name — the extra properties are forwarded to the preset:

import { ConventionalChangelog } from 'conventional-changelog'
const generator = new ConventionalChangelog()
.readPackage()
.loadPreset({
name: 'conventionalcommits',
// options below
})

Alternatively, import the preset factory and hand its result to .config():

import createPreset from 'conventional-changelog-conventionalcommits'
generator.config(createPreset({ /* options */ }))
OptionTypeDefaultDescription
typesCommitType[]default typesCommit types to recognize, the section each appears under, and its visibility.
ignoreCommitsRegExpSkip commits whose message matches this pattern.
issuePrefixesstring[]['#']Prefixes recognized as issue references and linkified in subjects and breaking change notes.
scopestring | string[]Only include commits for the given scope(s) (or commits with no scope, unless scopeOnly is true); the scope is stripped from the output.
scopeOnlybooleanfalseWith scope, also exclude commits that have no scope.
preMajorbooleanfalseTreat the project as pre-1.0 when recommending a version bump.
formatIssueUrl(context, reference) => stringgit-host styleBuild the URL for an issue/PR reference.
formatCommitUrl(context, commit) => stringgit-host styleBuild the URL for a commit hash.
formatCompareUrl(context) => stringgit-host styleBuild the version comparison URL in the release heading.
formatUserUrl(context, user) => stringgit-host styleBuild the URL for an @user mention.
formatNoteTitle(context, title) => stringsee note groupsBuild the heading for a note group.
formatNoteIcon(context, title) => string for breaking changesBuild the icon shown before a note group heading.

Controls which commit types show up and where. Each entry is:

interface CommitType {
type: string // commit type, e.g. "feat"
section?: string // heading the commits appear under
effect?: 'bump' | 'changelog' | 'hidden' // default: 'bump'
scope?: string // restrict this entry to a single scope
}

effect decides visibility and version impact:

  • bump (default) — shown in the changelog and counts toward the recommended version bump.
  • changelog — shown in the changelog, but does not affect the version bump.
  • hidden — parsed but omitted from the changelog.

Reveal the normally-hidden docs commits under their own section, without letting them drive a release:

import createPreset, { DEFAULT_COMMIT_TYPES } from 'conventional-changelog-conventionalcommits'
createPreset({
types: DEFAULT_COMMIT_TYPES.map(entry =>
entry.type === 'docs'
? { ...entry, effect: 'changelog' }
: entry
)
})

Shown by default (effect: 'bump'):

TypeSection
feat, featureFeatures
fixBug Fixes
perfPerformance Improvements
revertReverts

Recognized but hidden (effect: 'hidden'): docs (Documentation), style (Styles), chore (Miscellaneous Chores), refactor (Code Refactoring), test (Tests), build (Build System), ci (Continuous Integration).

Scope filtering is useful in monorepos where each package owns a commit scope. When scope is set, matching commits are included and the scope prefix is stripped from each entry (it’s implied by the section):

// Commits scoped to "api" — plus scopeless commits
createPreset({ scope: 'api' })
// Only commits explicitly scoped to "api"
createPreset({ scope: 'api', scopeOnly: true })
// Several scopes
createPreset({ scope: ['api', 'core'] })

A commit may declare multiple comma-separated scopes (feat(api,core): …); it matches if any of them is in scope.

Footers listed in the parser’s noteKeywords become notes, and notes are grouped by their keyword above the commit sections. Out of the box the preset recognizes BREAKING CHANGE and BREAKING-CHANGE, but you can add your own:

new ConventionalChangelog()
.config(createPreset())
.commits({}, { noteKeywords: ['BREAKING CHANGE', 'BREAKING-CHANGE', 'SECURITY'] })
### ⚠ BREAKING CHANGES
* the config format has changed
### SECURITY
* fixed an XSS in the renderer

BREAKING CHANGE and BREAKING-CHANGE are merged into one group, and any other keyword becomes a group of its own, uppercased so that SECURITY and Security end up together. Groups are sorted by title.

Both parts of the heading are configurable — the title and the icon before it:

import { noteTitle } from '@conventional-changelog/template'
createPreset({
formatNoteTitle: (context, title) => (title.toUpperCase() === 'SECURITY'
? 'Security fixes'
: noteTitle(title)),
formatNoteIcon: (context, title) => (title === 'Security fixes' ? '🔒' : '⚠')
})

formatNoteTitle receives the keyword as it was written in the commit and its result is what notes are grouped by, so returning the same title for two keywords merges them. formatNoteIcon receives that result. The default formatNoteTitle is exported as noteTitle from @conventional-changelog/template.

Only breaking changes affect the recommended version bump — a SECURITY footer gets its own changelog section, but it does not make the release a major one.

For projects still on 0.x, preMajor: true softens the recommended bump: breaking changes bump the minor version and features bump the patch version. It affects version recommendations only, not the changelog text.

Each formatter builds one kind of link; the defaults derive GitHub/GitLab/Bitbucket-style URLs from the repository info. Override them to target a custom host or URL scheme:

createPreset({
formatCommitUrl: (context, commit) =>
`https://git.example.com/${context.owner}/${context.repository}/-/commit/${commit.hash}`
})
FormatterBuilds
formatCompareUrl(context)The previousTag...currentTag comparison link in the release heading.
formatCommitUrl(context, commit)The link on each commit’s short hash.
formatIssueUrl(context, reference)The link on each issue/PR reference.
formatUserUrl(context, user)The link on each @user mention.