Skip to main content

Changelog

Record individual changes and release versioned changelogs with a single command that guides you through each step.

Summary

The changelog command combines two workflows into one guided flow:

  • Recording a change (what happened).
  • Releasing accumulated changes (bump versions and write a CHANGELOG.md).

In interactive mode, a menu lets you pick which action to take. In non-interactive mode, the --record and --release flags drive the same workflows from scripts and CI/CD pipelines.

Recorded entries are stored as individual .md files in a .changelog/ directory at the monorepo root. When released, the entries are consumed, versions are bumped in each affected package.json, and a CHANGELOG.md is written (or updated) in the workspace directory.

Why Use This Command?

  • Combines the record-and-release lifecycle into one command instead of separate tools.
  • Interactive prompts guide you through package selection, category, description, and SemVer bump type. No flags to memorize.
  • The --record and --release flags enable the same workflow in CI/CD without prompts.
  • The dry run option lets you preview every change before any file is touched.

Use Cases

  • Solo projects — Record a change and release it in the same session without learning a separate versioning tool.
  • Team workflows — Each contributor records changes in their PR. A maintainer runs the release step when ready.
  • CI/CD automation — Use --record in a pipeline step to capture changes, then --release in a publish step to bump versions and write changelogs.
  • Migration from Changesets — Replace changeset add with nova utility changelog --record and changeset version with nova utility changelog --release.

Requirements

  • Node.js runtime — Use any Node.js LTS release with either the installed nova CLI or npx.
  • Project root — Run the command from the directory containing the top-level package.json (monorepos included).
  • Nova config — A valid nova.config.json must exist with at least one non-freezable workspace defined.

Usage

You can run this command in two ways:

Options

FlagDescription
--recordRecord a change. Prompts for missing values unless all flags are provided.
--releaseRelease accumulated changes.
-p, --package <name>Package name for recording.
-c, --category <category>Category: updated, fixed, added, removed.
-b, --bump <type>Bump type: major, minor, patch.
-m, --message <message>Change description.
-d, --dry-runRun without writing any files.

How It Works

Record Flow

  1. Select package — Auto-selects if only one non-freezable workspace exists. Otherwise prompts.
  2. Select category — Choose from Updated, Fixed, Added, or Removed.
  3. Enter description — Free-text description of the change.
  4. Select bump type — Pre-selected based on category (Added/Updated = minor, Fixed = patch, Removed = major). Override if needed.
  5. Save — Writes an entry file to .changelog/ with a random adjective-noun-verb filename.

Release Flow

Steps 4–6 run once per releasing package in a loop. Step 7 runs once after all packages are processed.

  1. Read entries — Collects all .md files from .changelog/.
  2. Show summary — Lists entries grouped by package with the computed version bump (highest bump wins).
  3. Confirm — Interactive only. Non-interactive mode (--release) skips this step.
  4. Bump version — Updates the version field in each affected package.json.
  5. Write CHANGELOG.md — Prepends a new version section. Creates the file if it does not exist.
  6. Stamp sentinels — Replaces every @since UNRELEASED and @deprecated UNRELEASED tag in the package's src/ tree (.ts and .tsx files) with the new version. Skipped when the new version is a prerelease (contains a hyphen). Fails the release with a non-zero exit code if any sentinel survives after stamping.
  7. Clean up — Deletes consumed entry files from .changelog/.

Non-Zero Exit Code

The command exits with code 1 when validation fails (invalid flags, missing config, unknown package). CI pipelines that use this command will fail the step on errors.

UNRELEASED Sentinel Convention

When you add or change a public API member, tag it with the literal sentinel @since UNRELEASED (or @deprecated UNRELEASED) rather than a hand-written version number. The release step stamps the real version at release time, so you never have to guess or update the tag manually.

  • Write @since UNRELEASED for new members and @deprecated UNRELEASED for members being deprecated.
  • Never write a concrete version (e.g., @since 1.3.0) for unreleased code — it will be wrong if the bump type changes before release.
  • Concrete versions are only appropriate for members that have already shipped in a published release.
src/my-feature.ts
ts
// Before release (what you write):

/**
 * Returns the current config version.
 *
 * @since UNRELEASED
 */
export function getConfigVersion(): string { ... }

// After `nova utility changelog --release` (what gets stamped):

/**
 * Returns the current config version.
 *
 * @since 1.4.0
 */
export function getConfigVersion(): string { ... }

Entry File Format

Each recorded change is stored as an individual .md file in .changelog/:

.changelog/brave-cats-jump.md
markdown
---
package: "@cbnventures/nova"
category: added
bump: minor
---

New ESLint rule for switch case blocks.

CHANGELOG.md Format

Released entries are written in the following format. Headings are ordered as UPDATED, FIXED, ADDED, REMOVED.

Empty headings are omitted.

packages/nova/CHANGELOG.md
markdown
# @cbnventures/nova

## 1.3.0 - 2026-02-25

### FIXED
- Crash in initialize command.

### ADDED
- New ESLint rule for switch case blocks.

Examples

Migration from Changesets

For users migrating from the Changesets workflow, Nova provides equivalent flags under nova utility changelog:

CommandEquivalentWhat It Does
nova utility changelog --recordchangeset addRecord a change with -p, -c, -b, -m flags.
nova utility changelog --releasechangeset versionRelease accumulated changes, bump versions, and stamp @since/@deprecated UNRELEASED tags in source.

Shorten long commands with scripts

Nova bundles many tools in one package, so commands can be verbose. Shorten them by adding aliases to the "scripts" field in your root package.json (the one at the monorepo root):

package.json
json
{
  "scripts": {
    "changelog:record": "nova utility changelog --record",
    "changelog:release": "nova utility changelog --release"
  }
}

Then run npm run changelog:record or npm run changelog:release.

Troubleshooting

  • "No eligible (non-freezable) workspaces found" — Confirm that nova.config.json has at least one workspace with a trackable or distributable workspace policy.
  • "Cannot use --record and --release together" — These flags are mutually exclusive. Run them as separate commands.
  • "Non-interactive record requires --package, --category, --bump, and --message" — All four flags are required when using --record. Omit --record for interactive mode.
  • "No changelog entries found" — The .changelog/ directory is empty or does not exist. Record at least one change before releasing.
  • "Package not found in nova.config.json" — The --package value must match the name field of a non-freezable workspace in nova.config.json.
  • "UNRELEASED sentinel survived stamping" — The release step found one or more @since UNRELEASED or @deprecated UNRELEASED tags in src/ that were not replaced. This means a file was added or moved after the stamp pass searched it, or the file extension is not .ts or .tsx. Locate the surviving tag with grep -r "UNRELEASED" src/ and update it manually to the released version, then re-run any post-release steps.