Skip to content

semrel vs semantic-release vs goreleaser — Comparison

The release automation market has several established tools. This page gives you the information to choose the right one — or migrate from what you have.

semrelsemantic-releasegoreleaserrelease-pleaserelease-itchangesets
RuntimeNoneNode.js + npmNoneNode.js + npmNode.js + npmNode.js + npm
Install size~12 MB~350 MB~45 MB~300 MB~200 MB~150 MB
Air-gap ready✅ Native
Cold-start overhead~0 ms30–60 s (Node setup)~0 ms30–60 s30–60 s30–60 s

semantic-release is the pioneer of commit-driven semantic versioning and is widely used across thousands of enterprise pipelines. semrel was built to replicate its behaviour without the runtime cost.

Integrating semantic-release into a Go, Rust, or C++ pipeline requires:

Terminal window
# Added to every pipeline job:
actions/setup-node@v4 # 30-60 seconds on cold runners
npm install -g semantic-release # 28+ direct deps, 400+ transitive

On a minimal Alpine Linux runner or Docker-in-Docker environment this means pulling a full Node.js runtime into a container that otherwise contains only a Go toolchain.

semrel replaces the entire block with:

Terminal window
curl -L https://github.com/SemRels/semrel/releases/latest/download/semrel_linux_amd64.tar.gz | tar -xz
./semrel release

semantic-release is known to time out in repositories with many tags and branches. At 460 tags and 65 branches, reported execution times exceed 35 minutes due to sequential Git history traversal and API calls.

semrel is compiled Go — it traverses git log and queries forge APIs concurrently. Typical execution time on the same repository profile: under 90 seconds.

semantic-release installs 28 direct npm dependencies and hundreds of transitive packages on every pipeline run. The npm ecosystem has been the target of repeated supply-chain attacks.

semrel is a single statically compiled binary. There are no node_modules, no runtime package resolution, and no transitive dependency attack surface.

Both semrel and semantic-release support routing commits to bump levels by scope. semrel’s rules array accepts an optional scope field — including scope: false to match only commits with no scope at all:

# semrel (.semrel.yaml)
rules:
- type: deps
scope: major
bump: major
- type: deps
scope: minor
bump: minor
- type: deps
scope: patch
bump: patch
- type: feat
bump: minor
// semantic-release (package.json)
{
"releaseRules": [
{ "type": "deps", "scope": "major", "release": "major" },
{ "type": "deps", "scope": "minor", "release": "minor" }
]
}

Migrate in ~15 minutes

  1. Remove semantic-release config from package.json
  2. Install semrel
  3. Run semrel release --dry-run — the output should match your previous releases

Equivalent config mapping:

semantic-releasesemrel equivalent
@semantic-release/githubprovider-github plugin
@semantic-release/gitlabprovider-gitlab plugin
@semantic-release/changeloggenerator-changelog-md plugin
@semantic-release/gitbuilt-in git commit step
@semantic-release/npmupdater-npm plugin
@semantic-release/execany shell script via hook-*
releaseRules[].scoperules[].scope (string or false)

For a detailed step-by-step migration guide, see From semantic-release to semrel.


goreleaser and semrel solve different problems and are commonly used together.

Concernsemrelgoreleaser
What version is this release?✅ Calculates from commits❌ You provide the tag
Compile for linux/arm64, darwin/amd64, etc.❌ Not its job✅ Core feature
Create GitHub/GitLab release with assets✅ Via provider plugins✅ Core feature
Generate changelog✅ Via generator pluginsPartial (via templates)
Publish to Docker, Homebrew, npm, PyPI✅ Via updater + packager + publisher plugins✅ Core feature
Monorepo versioning✅ Free✅ Free (OSS plan)

Recommended combined workflow:

# GitHub Actions
- name: Compute next version
run: semrel release --dry-run --output json > semrel-output.json
- name: Build & distribute
uses: goreleaser/goreleaser-action@v6
with:
args: release
env:
GORELEASER_CURRENT_TAG: ${{ fromJson(steps.prev.outputs.json).nextVersion }}

For a step-by-step migration guide, see From goreleaser to semrel.


release-please (by Google) uses a pull-request-first model. Instead of releasing on every push, it:

  1. Accumulates commits into a “release PR”
  2. A human merges the PR to trigger the release
Concernsemrelrelease-please
Fully automated (no PR gate)❌ PR required
Conventional Commits
Supports GitLab / Gitea❌ GitHub only
Plugin extensibility✅ Any binary❌ Hardcoded updaters
Node.js dependency❌ None✅ Required

Choose release-please if your team requires human sign-off before every release. Choose semrel for fully hands-off CI releases or non-GitHub forges.

For a step-by-step migration guide, see From release-please to semrel.


release-it is a popular JavaScript-based release tool with an interactive CLI mode. It supports Conventional Commits, changelogs, npm publishing, and GitHub releases.

Concernsemrelrelease-it
RuntimeNoneNode.js + npm
Conventional Commits auto-bump
Scope-based bump rules
Interactive release wizard
Air-gap / offline pipelines
Supply-chain exposureNoneMedium (npm deps)
GitLab / Gitea / BitbucketPartial (GitLab plugin)
Plugin languageAny binaryJS only

release-it is a good fit for JavaScript/TypeScript projects that already use Node.js in CI and want an interactive experience. Choose semrel for any non-JS tech stack, air-gapped environments, or when supply-chain hardening matters.


changesets is JavaScript/TypeScript-centric and requires developers to manually create changeset files describing their changes. It does not read Conventional Commits automatically.

Concernsemrelchangesets
Auto-bump from commits❌ Manual changeset files
Conventional Commits
Developer overheadNoneHigh (per-PR changeeset)
Monorepo support
Non-JS projects❌ Designed for JS/TS
RuntimeNoneNode.js + npm

Choose semrel if you want zero developer overhead — just write Conventional Commits and CI handles the rest. changesets suits large JS monorepos where fine-grained human control over each package’s version bump is preferred over automation.


Do you need zero Node.js in your pipeline?
→ Yes → semrel ✅
→ No → any tool works
Do you need air-gap / fully offline CI?
→ Yes → semrel ✅
→ No → any tool works
Do you need automated versioning from commit messages?
→ Yes → semrel, semantic-release, or release-it
→ No → goreleaser (tag-based)
Do you need scope-based bump rules (e.g. deps(major))?
→ Yes → semrel or semantic-release ✅
→ No → any tool works
Do you need cross-platform Go binary compilation?
→ Yes → goreleaser (can combine with semrel)
→ No → semrel is sufficient
Do you want human PR approval before release?
→ Yes → release-please
→ No → semrel ✅
Is your project exclusively JavaScript/TypeScript?
→ Yes, and you want interactive releases → release-it
→ Yes, and you want manual version control → changesets
→ No → semrel ✅
Do you need GitLab, Gitea, or Bitbucket support?
→ Yes → semrel ✅
→ No → any tool works