semantic-release-action: a GitHub Action wrapper that pins and versions semantic-release
GitHub Action for Semantic Release
At a glance
- What is it?
- cycjimmy/semantic-release-action is a JavaScript GitHub Action that runs semantic-release inside a workflow, with inputs for the semantic-release version range, release branches, plugins, dry run and working directory, and a bundled semantic-release 25.0.9. It suits a team already on semantic-release that wants the toolchain pinned in the workflow, and it does nothing for a team that has not yet chosen a release automation.
- Who is it for?
- semantic-release-action is worth adopting for a team that already uses semantic-release and wants its version and its plugin set declared in the workflow rather than resolved at run time, because the action bundles semantic-release 25.0.9 and lets you pin a different version range, and because its branch input makes multi-channel release layouts explicit instead of leaving them to a config file.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 4 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Three setup steps, and the action only handles the third
The usage section is short, and its structure makes the point that this action is a convenience layer, not a release system.
Step one is to set any Semantic Release Configuration in your repository. Step two is to add secrets for the Semantic Release Authentication environment variables. Step three is to add a workflow file to your repository to create custom automated processes.
The basic workflow is the standard pair of steps:
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Semantic Release
uses: cycjimmy/semantic-release-action@v8
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}The token is passed through the environment rather than through an input, which is the convention semantic-release itself expects, and the action is referenced at the major version v8.
The two configuration steps are outside the action's control. It does not write your semantic-release config, and it does not create the secrets. What it adds over running semantic-release yourself in a workflow step is a pinned dependency set, a set of inputs that let you move the configuration into the workflow, and a bundled version that you can override.
The package is published as @cycjimmy/semantic-release-action, the main entry is index.js, and the type is module. The runtime dependencies are @actions/core and @actions/io for the action plumbing, plus semantic-release itself at 25.0.9, @semantic-release/git and @semantic-release/changelog. The test command runs the Node test runner over the test directory, and the repository has a src/ directory alongside index.js, a release.config.js, an action.yml and a docs/ directory.
The inputs move release configuration into the workflow
The input table is the substance of the action, and it is worth reading as a list of decisions that a team can make in YAML rather than in a config file.
semantic_version specifies a version range for semantic-release, and the minimum supported semantic-release version is v20, with older versions failing with an error. The example shows a specific version with a comment recommending a version range instead, and the note about specifying a range applies to the action below @v4. If no version range is given with the action at v8, semantic-release@latest is used.
branches is the branches on which releases should happen, and it also requires semantic-release v20 or above. It overrides the branches attribute in your configuration file, and if neither side has it, semantic-release uses its own defaults. The bundled semantic-release 25.0.9 defaults are the maintenance pattern plus master, main, next, next-major, and beta and alpha prereleases.
extra_plugins takes extra plugins for pre-install. dry_run runs semantic-release in dry-run mode. ci runs it with CI support. unset_gha_env unsets the GITHUB_ACTIONS environment variable. extends uses a shareable configuration. working_directory points semantic-release at another directory. tag_format specifies the format of the tag, which the table notes is useful for monorepos. repository_url is the Git repository url, defaulting to the current repository. skip_npm_plugin skips the @semantic-release/npm default plugin, which the table notes is useful for non-Node.js projects.
So the action is a thin, declarative surface over semantic-release's own configuration, and the interesting question for an adopter is which of those eleven decisions you want in the workflow and which you want in the config file.
Branch order decides which dist-tag your release lands on
The documentation carries a warning about branch ordering that is the most practically useful thing in the whole readme, and it is a class of bug that only shows up in production.
The note says semantic-release treats the first release branch that exists in your repository as the default one, published to the latest npm dist-tag and as the Latest GitHub Release, and every other release branch gets a distribution channel named after the branch. With the default branch list, if your repository still has a leftover master branch next to main, releases from main would be published to the main npm dist-tag instead of latest, and their GitHub Releases would be flagged as pre-releases.
That is a specific and plausible failure: a repository created on master, migrated to main, never deleted master, and now publishing to the wrong npm tag. The advice is to list the default branch first and remove stale master branches.
The branches input makes that explicit, and the example config is a maintenance-style pattern plus main, next and next-major, with beta and alpha prerelease objects carrying a name and a prerelease flag. The example input is the same shape written as YAML, and it shows the same branches list the semantic-release defaults use, with main moved to the front.
One detail is worth flagging: the branches input is evaluated as a JavaScript expression, which means the value is executed rather than parsed. That gives flexibility, and it also means the input is a place where a workflow can execute code, so it belongs in the same trust category as the rest of your workflow.
GITHUB_TOKEN cannot push to a protected branch, and that is the most common setup failure
The action carries an IMPORTANT note that is more about GitHub than about semantic-release: GITHUB_TOKEN does not have the required permissions to operate on protected branches.
The fix is to replace GITHUB_TOKEN with a Personal Access Token when you are using the action for protected branches. There is a second, subtler part. If you are using the @semantic-release/git plugin for protected branches, the documentation says to avoid persisting credentials as part of actions/checkout@v7 by setting the parameter persist-credentials: false, because that credential does not have the required permission to operate on protected branches either.
So a protected-branch setup needs three things: a Personal Access Token in place of GITHUB_TOKEN, persist-credentials set to false on the checkout step so the default token is not sitting on disk, and the @semantic-release/git plugin configured to push with your token. None of that is the action's fault; it is the shape of GitHub Actions, and the action's documentation is unusually clear about it.
The private package case is simpler. To publish to the npm GitHub Packages Registry you configure the registry in your package.json:
{
"publishConfig": {
"registry": "https://npm.pkg.github.com"
}
}The action itself has no special handling for that beyond running semantic-release, which reads the publishConfig like any other npm publish.
A maintained wrapper with a fast release line
The maintenance picture is unusually good for a third party action, and that is the main argument for using it rather than calling semantic-release directly.
The last three releases are v8.1.1 on 2026-10-16, v8.1.2 on 2026-10-16 and v8.1.3 on 2026-10-19, and the last push to the repository was on 2026-10-19. The action is versioned in step with the semantic-release it bundles, and the package version in package.json is 8.1.3, matching the tag. The package is at semantic-release 25.0.9.
The reason a team would want that maintenance is specific. semantic-release itself is a fast-moving dependency tree, and resolving it at run time inside a workflow means your release process can change behaviour without you touching a file. Pinning the version of semantic-release that performs your releases is a real operational benefit, and this action is a way to do that with the version expressed in the workflow rather than in a lockfile that the release job does not use.
The licence is MIT, the repository is not archived, and the homepage for the action is its GitHub Marketplace listing, with the release date and workflow badges at the top of the readme showing whether the latest build and the latest tag line up.
Where semantic-release-action is the wrong tool
The first limit is that it presumes semantic-release. Steps one and two of the usage, the configuration file and the authentication secrets, are the whole of semantic-release, and the action only wraps the third step. A team that has not yet decided how releases should work, or that has chosen a different tool, gets nothing here.
The second is the duplication risk. The inputs overlap with the semantic-release configuration file, and the branches input explicitly overrides the branches attribute in that file. A project that sets branches in both places has two sources of truth where one is silently winning, and the documentation says the input wins. The same applies to extends, which pulls in a shareable configuration, and to extra_plugins, which pre-installs plugins that the config file might also pull in. A team that spreads its release configuration across a config file, a shared preset and the workflow has made its release process harder to reason about, not easier.
The third is the v20 floor. The minimum supported semantic-release is v20, and older versions fail with an error rather than degrading. The branches input also requires v20 or above. That is not a problem for a new project, but it is a hard boundary for a team on an older semantic-release that wants to move the configuration into the workflow without first upgrading the tool itself.
The fourth is what the action does not handle. The README does not describe how the action reports back to a GitHub check, whether it fails the job on a dry run, or how it behaves when the semantic-release config file is missing or invalid. Those are the questions a release step is judged on, and the answer here is that it runs semantic-release, so you need to know what semantic-release does.
The fifth is the trust surface of the branches input, already noted, which is a reminder that a workflow file is code and this action makes it more obviously so.
Editorial conclusion
semantic-release-action is worth adopting for a team that already uses semantic-release and wants its version and its plugin set declared in the workflow rather than resolved at run time, because the action bundles semantic-release 25.0.9 and lets you pin a different version range, and because its branch input makes multi-channel release layouts explicit instead of leaving them to a config file. It is the wrong tool for a team that has not picked a release automation, and it is the wrong tool if you want semantic-release to resolve its own plugins at run time. Before you adopt it, check the three things the documentation makes explicit: that the minimum supported semantic-release is v20, since older versions fail with an error; that the branches input requires semantic-release v20 or above and overrides the branches attribute in your configuration file; and the GITHUB_TOKEN permission problem, because the default token cannot operate on protected branches and you need a Personal Access Token there, with persist-credentials set to false on actions/checkout when you use the @semantic-release/git plugin.
Frequently asked questions
How do I add the semantic-release-action to a GitHub Actions workflow?
Add a checkout step and a step that uses cycjimmy/semantic-release-action@v8, passing GITHUB_TOKEN and NPM_TOKEN through the env block from your repository secrets. Before that you need a semantic-release configuration in the repository and the authentication secrets added.
Why does semantic-release publish to the wrong npm dist-tag with this action?
Semantic-release treats the first release branch that exists in the repository as the default one, publishing it to the latest dist-tag, and gives every other release branch a channel named after it. A leftover master branch next to main makes main the second branch, so releases land on the main dist-tag and their GitHub Releases are flagged as pre-releases. List the default branch first and delete the stale one.
What is the minimum semantic-release version this action supports?
Version 20. Older semantic-release versions fail with an error. The branches input also requires semantic-release v20 or above, and the action bundles semantic-release 25.0.9. If you do not set a semantic_version range with the action at v8, semantic-release@latest is used.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/cycjimmy-semantic-release-action)Was this useful?