auto, lerna, release-it, semantic-release, and standard-version are all tools designed to automate parts of the software release process—particularly versioning, changelog generation, and publishing—for JavaScript/TypeScript projects. They interpret commit history (often following Conventional Commits) to determine the next version number, generate human-readable changelogs, tag releases, and in some cases publish to npm or GitHub. While they share overlapping goals, they differ significantly in scope, integration depth, configuration complexity, and suitability for monorepos versus single-package repositories.
Managing version numbers, changelogs, Git tags, and npm publishes manually is error-prone and time-consuming. These five tools aim to automate that workflow—but they take very different approaches. Let’s compare how they handle core release tasks.
All five tools rely on Conventional Commits (e.g., feat: add button, fix: resolve crash) to decide whether to bump patch, minor, or major versions—but their enforcement and flexibility vary.
semantic-release is the strictest: it requires Conventional Commits and will skip a release if no valid commits are found since the last tag.
// .releaserc.json (semantic-release)
{
"branches": ["main"],
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator"
]
}
// No config needed for basic Conventional Commits support
standard-version also assumes Conventional Commits by default but allows custom parsers via --skip.changelog or custom scripts.
# standard-version CLI
npx standard-version --release-as minor
# Or let it auto-detect from commits
npx standard-version
release-it doesn’t enforce any commit format—it lets you choose the version interactively or via flags. You can add Conventional Commits support with the @release-it/conventional-changelog plugin.
// .release-it.json (with conventional plugin)
{
"plugins": {
"@release-it/conventional-changelog": {
"preset": "angular"
}
}
}
auto uses GitHub labels (like major, minor, patch) on pull requests to determine version bumps, though it can also read Conventional Commits via plugins.
// .autorc
{
"plugins": ["npm", "conventional-commits"]
}
// Without the plugin, it uses PR labels instead of commit messages
lerna (in versioning mode) reads Conventional Commits when using --conventional-commits, but only in fixed/independent mode for monorepos.
# lerna version with Conventional Commits
npx lerna version --conventional-commits --yes
This is where the biggest divide appears.
lerna was built for monorepos. It can version and publish dozens of packages in one command, respecting dependencies between them.
# lerna handles all packages in packages/*
npx lerna publish --conventional-commits --yes
auto also supports monorepos via its monorepo plugin, generating per-package changelogs and publishing independently.
// .autorc for monorepo
{
"plugins": ["npm", "monorepo"]
}
semantic-release, release-it, and standard-version are primarily designed for single-package repos. Using them in monorepos requires looping over packages manually or using external tooling (like nx or custom scripts).
# Example: running standard-version in each package (not built-in)
for dir in packages/*; do
cd "$dir" && npx standard-version
done
semantic-release runs only in CI. It never prompts for input and will publish automatically if conditions are met.
# GitHub Actions example
- name: Release
run: npx semantic-release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
release-it is designed for interactive use but can run non-interactively in CI with --ci.
# Local interactive release
npx release-it
# CI non-interactive
npx release-it --ci
standard-version is local-only—it updates files but doesn’t push tags or publish. You must add those steps yourself.
npx standard-version
git push --follow-tags origin main
npm publish
auto and lerna can work in both modes, but auto shines in CI with GitHub Actions, while lerna is often run locally or in CI with explicit flags.
All tools generate changelogs, but formatting and placement differ.
semantic-release and standard-version update CHANGELOG.md in the project root by default.
auto can generate per-package changelogs in monorepos or a single top-level one.
release-it updates CHANGELOG.md only if configured with the conventional-changelog plugin.
lerna updates a root CHANGELOG.md and optionally per-package ones with --changelog-preset.
semantic-release: Automatically publishes to npm and creates GitHub releases.release-it: Publishes to npm and GitHub if configured, but asks first by default.standard-version: Does not publish—only bumps version and updates changelog.lerna: Publishes all changed packages to npm (with lerna publish).auto: Publishes to npm and GitHub, with support for canary/beta releases.standard-version (zero config for basic use), semantic-release (sane defaults)release-it (simple JSON, but plugins add complexity), lerna (requires understanding monorepo modes)auto (plugin system, GitHub label setup, extensive hooks)As of 2024:
lerna is actively maintained, but its release functionality is considered legacy; the team recommends using semantic-release or changesets for new projects.auto, release-it, semantic-release, standard-version) are actively maintained with recent releases.semantic-releaselerna (if already using it) or autorelease-itstandard-versionautoChoose based on your team’s workflow—not just features. The best tool is the one that fits how you actually release software.
Choose auto if you need a highly extensible, plugin-driven release system that supports both single packages and monorepos, with deep GitHub integration (including automated pull request labeling, release notes, and canary releases). It’s ideal when your team already uses GitHub labels to manage workflow and wants fine-grained control over every release step without writing custom scripts.
Choose lerna if you’re managing a JavaScript monorepo with multiple interdependent packages and need built-in support for versioning and publishing across the entire workspace. While Lerna historically handled releases, its modern focus is on monorepo tooling; use it for publishing only if you’re already using Lerna for package management and want minimal additional tooling—but consider pairing it with another tool like semantic-release for fully automated CI-based releases.
Choose release-it if you want a flexible, interactive CLI tool that works well for single-package repos and gives you full manual control over each release step (version bump, git tag, npm publish, GitHub release). It’s great for teams that prefer human-in-the-loop releases but still want automation for repetitive tasks, and it supports plugins for extending behavior without being opinionated about commit conventions.
Choose semantic-release if you want a zero-config, fully automated release pipeline that runs exclusively in CI environments and strictly enforces semantic versioning based on Conventional Commits. It’s best suited for open-source or internal libraries where every merge to main should potentially trigger a release, and you want to eliminate manual versioning decisions entirely.
Choose standard-version if you need a simple, standalone CLI that bumps versions and generates changelogs based on Conventional Commits without publishing to npm or creating GitHub releases by default. It’s ideal for projects that want lightweight automation during local development or as part of a custom script, especially when publishing is handled separately or requires manual review.
auto is a tool designed to seamlessly automate the release workflow.
It is powered by semantic version labels on pull requests.
This approach does not require you to change your code or make any drastic changes to your current workflow.
While intended to run in a continuous integration (CI) environment, all auto commands can run locally as well.
auto is distributed through npm, but you can use it with a variety of package management platforms.
npm install auto
For auto installation in non-npm environments follow these instructions.
Getting started with auto is super easy.
If your project is already published or has releases then you need to make sure that your last release is tagged and that it's the Latest Release on GitHub.
To tag your last release find the last commit where you bumped the version and run the following commands with your version number.
git tag v1.2.3
git push --tags
Then on GitHub go to your project's releases and click Draft a new release.
In the Tag version field enter the version number you just tagged and click Publish release.
(OPTIONAL) Initialize all options and configure label text.
If this is not run then auto will use the default configuration.
This command will produce an .autorc.
You can configure most flags and all labels/changelogTitles.
auto init
All options can also be configured via the .autorc file.
As CLI options you supply them in snake-case (--foo-bar), but as .autorc options you supply them in camelCase (fooBar),
Exclusive options (extends, labels) can only be set in the .autorc and do not exist as CLI flags.
Any option in the .autorc will get overridden by the CLI flags if provided.
The following are options that might be more useful to set in the .autorc than with a flag:
baseBranch Configure what your repo considers the base branch.
plugins Specify your plugins to load
githubApi If you are using enterprise github, `auto` lets you configure the github API URL that it uses.
githubGraphqlApi If you are using enterprise github and your company hosts the graphql at some other URL than the
`githubApi`, you can use `githubGraphqlApi` to set the base path for `auto`. The `githubGraphqlApi` gets
merged with `/graphql` to build the final URL.
Configure environment variables
You must configure some environment variables for publishing and releasing to work properly.
GH_TOKEN - Used for updating the changelog and publishing the GitHub releaseNPM_TOKEN - Used to publish to npm. (only with NPM plugin)Local .env:
You can also store these values in a local file at the root of your project named .env.
Make sure to add this file to your .gitignore so you don't commit any keys!
These environment variables will override any variable already set on the process.
This enables you to have a per project configuration that isn't effected by your global setup.
PROJECT_ROOT/.env:
GH_TOKEN=YOUR_TOKEN
NPM_TOKEN=PUBLISH_TOKEN
Create your project's labels on github. If a label already exist, it will be updated.
The types of labels that auto uses are:
To create the labels for your project on GitHub, run the following command with your GH_TOKEN.
GH_TOKEN=YOUR_TOKEN auto create-labels
# or with .env file
auto create-labels
Set up script
auto is written so that each tool it exposes is useful in isolation.
To version, changelog, publish and release your code all at the same time we've included the shipit tool.
This tool takes the default auto workflow and puts it into one command.
It will:
baseBranchbaseBranch{
"scripts": {
"release": "auto shipit"
}
}
For detailed setup instructions,refer here
--help)$ auto --help
auto
Generate releases based on semantic version labels on pull requests, and
other pull request automation tools.
Synopsis
$ auto <command> <options>
Setup Command
init Interactive setup for minimum working configuration.
info Determine the environment and check if auto is set up correctly
create-labels Create your project's labels on github. If labels exist it will update them.
Pull Request Interaction Commands
label Get the labels for a pull request. Doesn't do much, but the return value lets you write you own
scripts based off of the PR labels!
comment Comment on a pull request with a markdown message. Each comment has a context, and each context only
has one comment.
pr-check Check that a pull request has a SemVer label
pr-status Set the status on a PR commit
pr-body Update the body of a PR with a message. Appends to PR and will not overwrite user content. Each
comment has a context, and each context only has one comment.
Release Commands
version Get the semantic version bump for the given changes. Requires all PRs to have labels for the change
type. If a PR does not have a label associated with it, it will default to `patch`.
changelog Prepend release notes to `CHANGELOG.md`, create one if it doesn't exist, and commit the changes.
release Auto-generate a github release
shipit Context aware publishing.
1. call from base branch -> latest version released (LATEST)
2. call from prerelease branch -> prerelease version released (NEXT)
3. call from PR in CI -> canary version released (CANARY)
4. call locally when not on base/prerelease branch -> canary version released (CANARY)
latest Run the full `auto` release pipeline. Force a release to latest and bypass `shipit` safeguards.
canary Make a canary release of the project. Useful on PRs. If ran locally, `canary` will release a canary
version for your current git HEAD. This is ran automatically from "shipit".
1. In PR: 1.2.3-canary.123.0 + add version to PR body
2. Locally: 1.2.3-canary.1810cfd
next Make a release for your "prerelease" release line. This is ran automatically from "shipit".
1. Creates a prerelease on package management platform
2. Creates a "Pre Release" on GitHub releases page.
Calling the `next` command from a prerelease branch will publish a prerelease, otherwise it will
publish to the default prerelease branch.
Global Options
-V, --version Display auto's version
-v, --verbose Show some more logs. Pass -vv for very verbose logs.
--repo string The repo to set the status on. Defaults to looking in the package definition
for the platform
--owner string The owner of the GitHub repo. Defaults to reading from the package definition
for the platform
--github-api string GitHub API to use
--plugins string[] Plugins to load auto with. (defaults to just npm)
-h, --help Display the help output
One caveat of auto is that you need to be mindful of merging multiple PRs at once. You must not merge a PR while another is publishing (ex: lerna publish). While this window is small, it exists and you should know about it.
auto works by looking at the git tree to calculate the version bump then makes commits for the CHANGELOG.md and the new version. If you merge a PR while another is publishing:
The one exception to this rule with when merging a bunch of PRs with skip-release labels.
You still can't merge a PR that triggers a release and then merge a PR with skip-release. This will result in problem 3 from above.
But you can merge a bunch of PRs with skip-release then merge a PR that triggers a release.
Because skip-release is present no commits are made and the release is fine!
If you are using enterprise Github, auto lets you configure the Github API URL that it uses. You can configure this by using the CLI option --github-api, by setting the value in your .autorc, or during auto init.