O
OctoLab Team
Guest
One of the most common uses of GitHub Actions in Node.js projects is to automate releases: calculate the next version, tag the repository, generate release notes and publish a GitHub Release (and optionally publish to NPM).
This release flow usually involves a few key steps:
In this article we will set up a GitHub Actions workflow that automates this process every time you push to
We want that, every time a push happens in our
Before going into detail, it is useful to understand how a GitHub Actions workflow is structured. The main elements are:
Trigger (on
Defines when the workflow is executed. It can be when pushing, opening a pull request, publishing a release, executing manually, etc.
In our case, we use push to
Job (jobs
Each workflow can have one or several jobs. A job is a set of tasks that are executed in the same environment.
All the steps of a job share the same filesystem and context. In our example, we have a single job called
Runner (runs-on
It is the operating system where the job is executed. GitHub provides hosted runners, such as
Steps (steps
These are the actions or commands that are executed within a job. They can be:
Now that we understand how a workflow is structured, let's analyze each of the steps that make up our workflow. We will see what each action does, why it is necessary and what additional configurations we could apply depending on the case.
This block indicates that the workflow will be triggered when you push to
This step downloads the code from the repository so that it is available within the runtime environment.
Some additional options that this action allows are:
For this case, just use it without extra configuration:
This action installs a specific version of Node.js, in our case version 22. It also allows you to configure dependency caching and more.
Other useful options are:
These steps execute the commands defined in your project and run Semantic Release to automate the versioning and release process:
With this flow you guarantee that every push to
Understanding how a workflow works in GitHub Actions is indispensable. It gives you control and helps you customize everything to your needs.
Now... if you don't feel like struggling with the syntax, that's fine too.
At OctoLab we offer you the ability to set up this same flow visually: you choose the actions, fill in the fields and it generates the YAML for you on the fly.
Without indentation errors
With built-in validations
Copy, paste and go.
This workflow is an excellent basis for automated, reliable releases in Node.js projects. It can be easily adapted to other needs: publishing to npm, updating changelogs automatically, multi-branch strategies, or running on multiple Node versions.
Continue reading...
This release flow usually involves a few key steps:
- Install dependencies to ensure the project can build.
- Build the project if your package/app requires compiled artifacts.
- Run Semantic Release to analyze commits, bump the version (major/minor/patch), create a tag and publish the release notes.
In this article we will set up a GitHub Actions workflow that automates this process every time you push to
main
. We will explain step by step what each part of the workflow does and why it is important.
The purpose of the workflow
We want that, every time a push happens in our
main
branch, a set of tasks runs to automate releases using Conventional Commits:- Analyzes commit messages and determines the next version (major/minor/patch)
- Creates a Git tag and generates release notes
- Publishes a GitHub Release
- (Optional) Publishes to npm if configured via plugins
General workflow structure
Code:
name: Releasing with Semantic Release
on:
push:
branches:
- main
jobs:
release:
name: release
runs-on: ubuntu-latest
steps:
- id: checkout-step
name: Checkout code
uses: actions/checkout@v4
- id: setup-node-step
name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "22"
- id: install-dependencies-step
name: Install dependencies
run: npm install
- id: build-step
name: Build package
run: npm run build
- id: semantic-release-step
name: Release with Semantic Release
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
run: npx semantic-release
What parts compose a GitHub Actions workflow?
Before going into detail, it is useful to understand how a GitHub Actions workflow is structured. The main elements are:
Trigger (on

Defines when the workflow is executed. It can be when pushing, opening a pull request, publishing a release, executing manually, etc.
In our case, we use push to
main
, which triggers a release attempt every time new commits land in the main branch.Job (jobs

Each workflow can have one or several jobs. A job is a set of tasks that are executed in the same environment.
All the steps of a job share the same filesystem and context. In our example, we have a single job called
release
.Runner (runs-on

It is the operating system where the job is executed. GitHub provides hosted runners, such as
ubuntu-latest
, windows-latest
or macos-latest
, but we also have the possibility to use self-hosted runners.Steps (steps

These are the actions or commands that are executed within a job. They can be:
- Reusable actions such as actions/checkout or actions/setup-node.
- Specific commands defined with run, such as
npm install
ornpx semantic-release
.
Step-by-step of our workflow
Now that we understand how a workflow is structured, let's analyze each of the steps that make up our workflow. We will see what each action does, why it is necessary and what additional configurations we could apply depending on the case.
on: push (branches: main)
This block indicates that the workflow will be triggered when you push to
main
. Semantic Release will then decide whether a new release should be created based on the commit history (using Conventional Commits).uses: actions/checkout@v4
This step downloads the code from the repository so that it is available within the runtime environment.
Some additional options that this action allows are:
- fetch-depth: 0 clones the entire repository history (by default only the current commit). Semantic Release may benefit from full history in some setups.
- ref: branch-name** you can set a specific branch
- path: subdirectory clone the code in a specific path
For this case, just use it without extra configuration:
Code:
- uses: actions/checkout@v4
uses: actions/setup-node@v4
This action installs a specific version of Node.js, in our case version 22. It also allows you to configure dependency caching and more.
Code:
- uses: actions/setup-node@v4
with:
node-version: "22"
Other useful options are:
- cache: βnpmβ enables dependency caching using actions/cache underneath
- check-latest: true** forces to use the latest available version that complies with the semver.
Working scripts
Code:
- run: npm install
- run: npm run build
- run: npx semantic-release
These steps execute the commands defined in your project and run Semantic Release to automate the versioning and release process:
- npm install will install all the project's dependencies.
- npm run build** will generate the final package or artifacts if your project needs a build step (libraries, apps, compiled bundles, etc.).
- npx semantic-release will: -- analyze commits following Conventional Commits, -- determine the next version (major/minor/patch), -- create a Git tag, -- generate release notes, and -- publish a GitHub Release (and optionally publish to npm if configured via plugins).
Token & config tips
- Expose a token with permissions to create tags/releases:
env: { GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} }
You can also use the defaultGITHUB_TOKEN
with proper write permissions.- Provide a Semantic Release configuration (in
package.json
underrelease
or in a.releaserc
file) with the plugins you need (e.g.,@semantic-release/github
,@semantic-release/changelog
,@semantic-release/npm
,@semantic-release/git
).- Ensure your commit messages follow Conventional Commits so Semantic Release can infer the correct next version.
Final result
With this flow you guarantee that every push to
main
goes through an automated release process, without manual tagging or copy-pasting release notes. You can integrate it with additional plugins/steps such as:- Automatic CHANGELOG.md updates and commits
- npm publishing with
@semantic-release/npm
- Multi-branch release strategies (e.g.,
next
,beta
) - Notifications (Slack, Discord, etc.)
Do you want to avoid writing it by hand? There is a more convenient way
Understanding how a workflow works in GitHub Actions is indispensable. It gives you control and helps you customize everything to your needs.
Now... if you don't feel like struggling with the syntax, that's fine too.
At OctoLab we offer you the ability to set up this same flow visually: you choose the actions, fill in the fields and it generates the YAML for you on the fly.



Conclusion
This workflow is an excellent basis for automated, reliable releases in Node.js projects. It can be easily adapted to other needs: publishing to npm, updating changelogs automatically, multi-branch strategies, or running on multiple Node versions.
If you prefer to use OctoLab we will be very grateful for your feedback!![]()
Continue reading...