<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: OctoLab Team</title>
    <description>The latest articles on Forem by OctoLab Team (@octolab).</description>
    <link>https://forem.com/octolab</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3413638%2Fa7713d59-6482-44e8-8caa-c79b8a56de4b.jpg</url>
      <title>Forem: OctoLab Team</title>
      <link>https://forem.com/octolab</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/octolab"/>
    <language>en</language>
    <item>
      <title>Automate Releases with Semantic Release and GitHub Actions (Step-by-Step)</title>
      <dc:creator>OctoLab Team</dc:creator>
      <pubDate>Sat, 30 Aug 2025 11:36:10 +0000</pubDate>
      <link>https://forem.com/octolab/automate-releases-with-semantic-release-and-github-actions-step-by-step-1a65</link>
      <guid>https://forem.com/octolab/automate-releases-with-semantic-release-and-github-actions-step-by-step-1a65</guid>
      <description>&lt;p&gt;One of the most common uses of GitHub Actions in Node.js projects is to &lt;strong&gt;automate releases&lt;/strong&gt;: calculate the next version, tag the repository, generate release notes and publish a GitHub Release (and optionally publish to &lt;a href="https://www.npmjs.com/" rel="noopener noreferrer"&gt;NPM&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;This release flow usually involves a few key steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Install dependencies&lt;/strong&gt; to ensure the project can build.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build the project&lt;/strong&gt; if your package/app requires compiled artifacts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run Semantic Release&lt;/strong&gt; to analyze commits, bump the version (major/minor/patch), create a tag and publish the release notes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this article we will set up a GitHub Actions workflow that automates this process every time you push to &lt;code&gt;main&lt;/code&gt;. We will explain step by step what each part of the workflow does and why it is important.&lt;/p&gt;

&lt;h3&gt;
  
  
  🎯 The purpose of the workflow
&lt;/h3&gt;

&lt;p&gt;We want that, every time a &lt;strong&gt;push&lt;/strong&gt; happens in our &lt;code&gt;main&lt;/code&gt; branch, a set of tasks runs to automate releases using Conventional Commits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Analyzes commit messages and &lt;strong&gt;determines the next version&lt;/strong&gt; (major/minor/patch)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Creates a Git tag&lt;/strong&gt; and &lt;strong&gt;generates release notes&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Publishes a GitHub Release&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;(Optional) Publishes to &lt;strong&gt;npm&lt;/strong&gt; if configured via plugins&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🧬 General workflow structure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Releasing with Semantic Release&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;release&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;checkout-step&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout code&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;setup-node-step&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Node&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;22"&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;install-dependencies-step&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build-step&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build package&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run build&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;semantic-release-step&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Release with Semantic Release&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GH_TOKEN }}&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx semantic-release&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ⚙️ What parts compose a GitHub Actions workflow?
&lt;/h3&gt;

&lt;p&gt;Before going into detail, it is useful to understand how a GitHub Actions workflow is structured. The main elements are:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trigger (on:)&lt;/strong&gt;&lt;br&gt;
Defines when the workflow is executed. It can be when pushing, opening a pull request, publishing a release, executing manually, etc.&lt;br&gt;
In our case, we use &lt;strong&gt;push&lt;/strong&gt; to &lt;code&gt;main&lt;/code&gt;, which triggers a release attempt every time new commits land in the main branch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Job (jobs:)&lt;/strong&gt;&lt;br&gt;
Each workflow can have one or several jobs. A job is a set of tasks that are executed in the same environment.&lt;br&gt;
All the steps of a job share the same filesystem and context. In our example, we have a single job called &lt;code&gt;release&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Runner (runs-on:)&lt;/strong&gt;&lt;br&gt;
It is the operating system where the job is executed. GitHub provides hosted runners, such as &lt;code&gt;ubuntu-latest&lt;/code&gt;, &lt;code&gt;windows-latest&lt;/code&gt; or &lt;code&gt;macos-latest&lt;/code&gt;, but we also have the possibility to use self-hosted runners.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Steps (steps:)&lt;/strong&gt;&lt;br&gt;
These are the actions or commands that are executed within a job. They can be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reusable actions such as &lt;em&gt;actions/checkout&lt;/em&gt; or &lt;em&gt;actions/setup-node&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Specific commands defined with run, such as &lt;code&gt;npm install&lt;/code&gt; or &lt;code&gt;npx semantic-release&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  🪜 Step-by-step of our workflow
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;
&lt;h4&gt;
  
  
  on: push (branches: main)
&lt;/h4&gt;

&lt;p&gt;This block indicates that the workflow will be triggered when you push to &lt;code&gt;main&lt;/code&gt;. Semantic Release will then decide whether a new release should be created based on the commit history (using Conventional Commits).&lt;/p&gt;
&lt;h4&gt;
  
  
  uses: actions/checkout@v4
&lt;/h4&gt;

&lt;p&gt;This step downloads the code from the repository so that it is available within the runtime environment.&lt;/p&gt;

&lt;p&gt;Some additional options that this action allows are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;fetch-depth: 0&lt;/strong&gt; clones the entire repository history (by default only the current commit). Semantic Release may benefit from full history in some setups.&lt;/li&gt;
&lt;li&gt;ref: branch-name** you can set a specific branch&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;path: subdirectory&lt;/strong&gt; clone the code in a specific path&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For this case, just use it without extra configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  uses: actions/setup-node@v4
&lt;/h4&gt;

&lt;p&gt;This action installs a specific version of Node.js, in our case version 22. It also allows you to configure dependency caching and more.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;22"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other useful options are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;cache: ‘npm’&lt;/strong&gt; enables dependency caching using &lt;em&gt;actions/cache&lt;/em&gt; underneath&lt;/li&gt;
&lt;li&gt;check-latest: true** forces to use the latest available version that complies with the &lt;em&gt;semver&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Working scripts
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run build&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx semantic-release&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These steps execute the commands defined in your project and run Semantic Release to automate the versioning and release process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;npm install&lt;/strong&gt; will install all the project's dependencies.&lt;/li&gt;
&lt;li&gt;npm run build** will generate the final package or artifacts if your project needs a build step (libraries, apps, compiled bundles, etc.).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;npx semantic-release&lt;/strong&gt; will:
-- analyze commits following &lt;strong&gt;Conventional Commits&lt;/strong&gt;,
-- determine the next version (major/minor/patch),
-- create a &lt;strong&gt;Git tag&lt;/strong&gt;,
-- generate &lt;strong&gt;release notes&lt;/strong&gt;, and
-- publish a &lt;strong&gt;GitHub Release&lt;/strong&gt; (and optionally publish to &lt;strong&gt;npm&lt;/strong&gt; if configured via plugins).&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Token &amp;amp; config tips&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Expose a token with permissions to create tags/releases:&lt;/strong&gt;
&lt;code&gt;env: { GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} }&lt;/code&gt;
You can also use the default &lt;code&gt;GITHUB_TOKEN&lt;/code&gt; with proper write permissions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Provide a Semantic Release configuration&lt;/strong&gt; (in &lt;code&gt;package.json&lt;/code&gt; under &lt;code&gt;release&lt;/code&gt; or in a &lt;code&gt;.releaserc&lt;/code&gt; file) with the plugins you need (e.g., &lt;code&gt;@semantic-release/github&lt;/code&gt;, &lt;code&gt;@semantic-release/changelog&lt;/code&gt;, &lt;code&gt;@semantic-release/npm&lt;/code&gt;, &lt;code&gt;@semantic-release/git&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ensure your commit messages follow Conventional Commits&lt;/strong&gt; so Semantic Release can infer the correct next version.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  ✅ Final result
&lt;/h3&gt;

&lt;p&gt;With this flow you guarantee that every push to &lt;code&gt;main&lt;/code&gt; goes through an automated release process, without manual tagging or copy-pasting release notes. You can integrate it with additional plugins/steps such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatic &lt;strong&gt;CHANGELOG.md&lt;/strong&gt; updates and commits&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;npm&lt;/strong&gt; publishing with &lt;code&gt;@semantic-release/npm&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Multi-branch release strategies (e.g., &lt;code&gt;next&lt;/code&gt;, &lt;code&gt;beta&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Notifications (Slack, Discord, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🐙 Do you want to avoid writing it by hand? There is a more convenient way
&lt;/h3&gt;

&lt;p&gt;Understanding how a workflow works in GitHub Actions is indispensable. It gives you control and helps you customize everything to your needs.&lt;/p&gt;

&lt;p&gt;Now... if you don't feel like struggling with the syntax, that's fine too.&lt;br&gt;
At &lt;a href="https://www.octolab.app/templates/semantic-release" rel="noopener noreferrer"&gt;OctoLab&lt;/a&gt; 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.&lt;/p&gt;

&lt;p&gt;✅ Without indentation errors&lt;br&gt;
✅ With built-in validations&lt;br&gt;
✅ Copy, paste and go.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧠 Conclusion
&lt;/h3&gt;

&lt;p&gt;This workflow is an excellent basis for &lt;strong&gt;automated, reliable releases&lt;/strong&gt; 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.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you prefer to use &lt;a href="https://www.octolab.app" rel="noopener noreferrer"&gt;OctoLab&lt;/a&gt; we will be very grateful for your feedback! 🤗&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>githubactions</category>
      <category>devops</category>
      <category>cicd</category>
      <category>semanticrelease</category>
    </item>
    <item>
      <title>Deploy your application on Vercel with GitHub Actions</title>
      <dc:creator>OctoLab Team</dc:creator>
      <pubDate>Wed, 20 Aug 2025 16:52:15 +0000</pubDate>
      <link>https://forem.com/octolab/deploy-your-application-on-vercel-with-github-actions-1lh2</link>
      <guid>https://forem.com/octolab/deploy-your-application-on-vercel-with-github-actions-1lh2</guid>
      <description>&lt;p&gt;A very common CI/CD pattern for frontend apps is: &lt;strong&gt;build in CI and deploy to production automatically when the code reaches&lt;/strong&gt; &lt;code&gt;main&lt;/code&gt;.&lt;br&gt;
If you use Vercel, you can do this with a &lt;strong&gt;short and reliable&lt;/strong&gt; GitHub Actions workflow that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;downloads your project's configuration and variables from Vercel,&lt;/li&gt;
&lt;li&gt;builds the app in CI,&lt;/li&gt;
&lt;li&gt;and deploys the already built artifacts to &lt;strong&gt;production&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this article, we'll walk through it step by step and I'll give you some tips to help you understand &lt;strong&gt;what each line does&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  🎯 Purpose of the workflow
&lt;/h3&gt;

&lt;p&gt;Every time there is a push to &lt;code&gt;main&lt;/code&gt;, the following should be executed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pull config&lt;/strong&gt; from Vercel (includes &lt;strong&gt;production&lt;/strong&gt; environment variables).&lt;/li&gt;
&lt;li&gt;Reproducible &lt;strong&gt;build&lt;/strong&gt; in CI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy&lt;/strong&gt; that artifact (without rebuilding in Vercel).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This will give you &lt;strong&gt;predictable&lt;/strong&gt; deployments that are easy to audit and debug.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧬 General workflow structure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Vercel PRO deployment&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;checkout-step&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout code&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;install-vercel-cli-step&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Vercel CLI&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install --global vercel@latest&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pull-vercel-env-info-step&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Pull Vercel Environment Information&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN&lt;/span&gt;
          &lt;span class="s"&gt;}}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build-vercel-artifacts-step&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build Project Artifacts&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vercel build --prod --token=${{ secrets.VERCEL_TOKEN }}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy-vercel-artifacts-step&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy Project Artifacts to Vercel&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;br&gt;
Create the secret &lt;code&gt;VERCEL_TOKEN&lt;/code&gt; in your repository (Settings → Secrets and variables → Actions).&lt;br&gt;
Either commit &lt;code&gt;.vercel/project.json&lt;/code&gt;, or provide &lt;code&gt;VERCEL_ORG_ID&lt;/code&gt; and &lt;code&gt;VERCEL_PROJECT_ID&lt;/code&gt; as secrets when you do vercel pull.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  🪜 Step by step
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;on: push (to main)&lt;/strong&gt;&lt;br&gt;
Each push to &lt;code&gt;main&lt;/code&gt; triggers the production pipeline. If you prefer to only deploy when merging by PR, simply avoid pushing directly to &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;uses: actions/checkout@v4&lt;/strong&gt;&lt;br&gt;
Download your code to the runner so that the following tools (Vercel CLI) have it available.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;npm install --global vercel@latest&lt;/strong&gt;&lt;br&gt;
Install the Vercel CLI.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; to avoid surprises, you can set version: vercel@xx (or whatever you use on your team).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;vercel pull --yes --environment=production&lt;/strong&gt;&lt;br&gt;
Bring the project configuration and production environment variables to &lt;code&gt;.vercel/&lt;/code&gt; on the runner.&lt;br&gt;
In CI there are no interactive questions, so we use &lt;code&gt;--yes&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.vercel/project.json&lt;/code&gt; in the repository or&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;VERCEL_ORG_ID&lt;/code&gt; and &lt;code&gt;VERCEL_PROJECT_ID&lt;/code&gt; as variables/secrets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;vercel build --prod&lt;/strong&gt;&lt;br&gt;
Builds in CI using your framework (Next.js, SvelteKit, etc.) or what is defined in &lt;code&gt;vercel.json&lt;/code&gt;.&lt;br&gt;
The result is stored in &lt;code&gt;.vercel/output&lt;/code&gt; and is exactly what you are going to deploy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;vercel deploy --prebuilt --prod&lt;/strong&gt;&lt;br&gt;
Uploads the already built artifact to production.&lt;br&gt;
With &lt;code&gt;--prebuilt&lt;/code&gt;, Vercel does not rebuild: what you tested in CI is what your user will see.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Final result
&lt;/h3&gt;

&lt;p&gt;With this workflow, each merge to &lt;code&gt;main&lt;/code&gt; runs a clean build and deploys that same artifact to production in Vercel. You get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reproducible builds,&lt;/li&gt;
&lt;li&gt;faster deploys,&lt;/li&gt;
&lt;li&gt;and clear CI logs for debugging.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🐙 Prefer to configure it visually?
&lt;/h3&gt;

&lt;p&gt;Writing workflows by hand gives you total control, but sometimes you want speed with built-in validations.&lt;/p&gt;

&lt;p&gt;With &lt;strong&gt;OctoLab&lt;/strong&gt;, you can set up this same pipeline visually: choose actions, fill in fields, and the YAML is generated instantly, ready to commit.&lt;/p&gt;

&lt;p&gt;👉 Try it out: &lt;a href="https://www.octolab.app/templates/vercel-pro-deployment" rel="noopener noreferrer"&gt;https://www.octolab.app/templates/vercel-pro-deployment&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🧵 Conclusion
&lt;/h3&gt;

&lt;p&gt;This workflow provides you with a clean &lt;strong&gt;CI → production&lt;/strong&gt; flow on every push to &lt;code&gt;main&lt;/code&gt;, using Vercel's recommended approach: &lt;strong&gt;pull → build → deploy&lt;/strong&gt;. It's easy to adapt to previews, monorepos, or strict reproducibility (fixed Node and CLI). &lt;/p&gt;

&lt;p&gt;Use it as a base and evolve it with caching, notifications, or environment gates as your team grows.&lt;/p&gt;

</description>
      <category>githubactions</category>
      <category>devops</category>
      <category>cicd</category>
      <category>vercel</category>
    </item>
    <item>
      <title>Publish your packages to NPM automatically with GitHub Actions</title>
      <dc:creator>OctoLab Team</dc:creator>
      <pubDate>Fri, 15 Aug 2025 10:31:21 +0000</pubDate>
      <link>https://forem.com/octolab/publish-your-packages-to-npm-automatically-with-github-actions-3ghj</link>
      <guid>https://forem.com/octolab/publish-your-packages-to-npm-automatically-with-github-actions-3ghj</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Automating publication prevents manual errors, speeds up releases, and forces you to maintain a repeatable and transparent process.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this article, we're going to create a GitHub Actions workflow that &lt;strong&gt;publishes to NPM&lt;/strong&gt; when you push to &lt;code&gt;main&lt;/code&gt;. The flow installs dependencies, runs tests, compiles, and, if all goes well, &lt;strong&gt;publishes&lt;/strong&gt; the package using a secure token stored as a secret.&lt;/p&gt;

&lt;h3&gt;
  
  
  🎯 What is the purpose of the workflow?
&lt;/h3&gt;

&lt;p&gt;Every time you merge changes to &lt;code&gt;main&lt;/code&gt;, we want to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install dependencies&lt;/li&gt;
&lt;li&gt;Run tests&lt;/li&gt;
&lt;li&gt;Build the package&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Publish&lt;/strong&gt; to NPM using secure credentials&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This standardizes the publishing process and reduces the risk of human error.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧬 General workflow structure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Publish to NPM&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;publish&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;publish&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout code&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Node&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;22"&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run tests&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run test&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build package&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run build&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Publish to NPM&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;JS-DevTools/npm-publish@v3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.NPM_TOKEN }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🛠️ What does each step do?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;on: push to main&lt;/strong&gt;&lt;br&gt;
Triggers the workflow when pushing to the &lt;code&gt;main&lt;/code&gt; branch. If you prefer to publish only with tags, you can change the trigger to &lt;code&gt;on: push: tags: - ‘v*’&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;actions/checkout@v4&lt;/strong&gt;&lt;br&gt;
Downloads the repository to the runner.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;actions/setup-node@v4&lt;/strong&gt;&lt;br&gt;
Configures Node.js (v22 in the example). You can enable &lt;code&gt;cache: ‘npm’&lt;/code&gt; to speed up installations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;npm ci / npm install&lt;/strong&gt;&lt;br&gt;
Installs dependencies. &lt;code&gt;npm ci&lt;/code&gt; is faster and more reproducible in CI if you use &lt;code&gt;package-lock.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;npm run test and npm run build&lt;/strong&gt;&lt;br&gt;
Verify that the package passes tests and compiles correctly before publishing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JS-DevTools/npm-publish@v3&lt;/strong&gt;&lt;br&gt;
Publish the package by reading &lt;code&gt;package.json&lt;/code&gt;. Use the token you pass through &lt;code&gt;with.token&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  🔐 Authentication with NPM: NPM_TOKEN
&lt;/h3&gt;

&lt;p&gt;To publish, you need a token in &lt;strong&gt;NPM&lt;/strong&gt; and save it as a secret in GitHub:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create an &lt;strong&gt;Automation Token&lt;/strong&gt; in your NPM account (recommended for CI; respects 2FA and allows automatic publishing).&lt;/li&gt;
&lt;li&gt;In GitHub, go to &lt;strong&gt;Settings&lt;/strong&gt; → &lt;strong&gt;Secrets and variables&lt;/strong&gt; → &lt;strong&gt;Actions&lt;/strong&gt; → &lt;strong&gt;New repository secret&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Create the secret &lt;code&gt;NPM_TOKEN&lt;/code&gt; with the value of the NPM token.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 If your package is scoped (e.g., &lt;code&gt;@your-org/package&lt;/code&gt;), make sure that &lt;code&gt;package.json&lt;/code&gt; contains &lt;code&gt;“name”: “@your-org/package”&lt;/code&gt; and &lt;code&gt;“publishConfig”: { ‘access’: “public” }&lt;/code&gt; if you want it to be public.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Example of &lt;code&gt;publishConfig&lt;/code&gt; in &lt;code&gt;package.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@tu-org/tu-paquete"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.2.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"publishConfig"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"access"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"public"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tag"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"latest"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🧪 Dry-run and version control
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Dry-run:&lt;/strong&gt; test the flow without actually publishing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Publish to NPM (dry run)&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;JS-DevTools/npm-publish@v3&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.NPM_TOKEN }}&lt;/span&gt;
    &lt;span class="na"&gt;dry-run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Versioning:&lt;/strong&gt; this flow publishes the version specified in &lt;code&gt;package.json&lt;/code&gt;. Be sure to &lt;strong&gt;update the version&lt;/strong&gt; before merging to &lt;code&gt;main&lt;/code&gt;.&lt;br&gt;
If you use automatic versioning (e.g., Conventional Commits + automatic releases), integrate that stage &lt;strong&gt;before&lt;/strong&gt; the publication step.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Final result
&lt;/h3&gt;

&lt;p&gt;With this workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You publish to NPM in a &lt;strong&gt;consistent and repeatable&lt;/strong&gt; manner.&lt;/li&gt;
&lt;li&gt;You avoid broken releases thanks to &lt;strong&gt;preliminary tests + builds&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You keep credentials secure with &lt;strong&gt;GitHub Secrets&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You reduce manual steps and time between merge and release.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🐙 Would you rather set it up with a visual interface?
&lt;/h3&gt;

&lt;p&gt;If you're interested in defining this flow with a visual interface and getting the YAML instantly, you can use &lt;strong&gt;OctoLab&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Step-by-step visual editor&lt;/li&gt;
&lt;li&gt;Dynamic fields for actions and tokens&lt;/li&gt;
&lt;li&gt;Real-time YAML preview&lt;/li&gt;
&lt;li&gt;Built-in validations&lt;/li&gt;
&lt;li&gt;Copy/download and you're done&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 Try it out: &lt;a href="https://www.octolab.app/templates/npm-publish" rel="noopener noreferrer"&gt;https://www.octolab.app/templates/npm-publish&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🧵 Conclusion
&lt;/h3&gt;

&lt;p&gt;Automating publication to NPM with GitHub Actions reduces friction and errors. With a simple configuration—tests, build, and a publish step with a secure token—you can standardize releases and focus on building value.&lt;/p&gt;

&lt;p&gt;If this was helpful, let me know what you would like to add to the template (tags, prereleases, monorepos, changelogs, etc.). Let's keep going!&lt;/p&gt;

</description>
      <category>githubactions</category>
      <category>devops</category>
      <category>cicd</category>
      <category>npm</category>
    </item>
    <item>
      <title>Verify your pull requests in NX monorepos with GitHub Actions</title>
      <dc:creator>OctoLab Team</dc:creator>
      <pubDate>Thu, 07 Aug 2025 09:33:53 +0000</pubDate>
      <link>https://forem.com/octolab/verify-your-pull-requests-in-nx-monorepos-with-github-actions-1e96</link>
      <guid>https://forem.com/octolab/verify-your-pull-requests-in-nx-monorepos-with-github-actions-1e96</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;One of the great advantages of GitHub Actions is its ability to automate validation flows tailored to your project structure. And monorepos created with NX are a perfect case in point.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this article, we will build a GitHub Actions workflow that automatically validates any pull request in an NX monorepo, running lint, tests, and compilation only on the affected projects. This allows us to speed up CI, reduce noise, and maintain code quality without wasting resources.&lt;/p&gt;

&lt;h3&gt;
  
  
  🎯 What is the purpose of this workflow?
&lt;/h3&gt;

&lt;p&gt;We want the following actions to be performed every time a pull request is opened:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Detect which parts of the monorepo have been affected&lt;/li&gt;
&lt;li&gt;Run lint only on those parts&lt;/li&gt;
&lt;li&gt;Run the relevant tests&lt;/li&gt;
&lt;li&gt;Compile the affected packages or applications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This ensures that only necessary tasks are executed and that errors are detected as soon as possible — something that is key in monorepos of a certain size.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧬 General structure of the workflow
&lt;/h3&gt;

&lt;p&gt;Below, I will show you the complete content of the workflow that we are going to analyze:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NX Pull request verify&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;verify&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;verify&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout code&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Node&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;22"&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run lint&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx nx affected --target=lint --head=HEAD --base=origin/main&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run tests&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx nx affected --target=test --head=HEAD --base=origin/main&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build package&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx nx affected --target=build --head=HEAD --base=origin/main&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's now take a step-by-step look at what each section does.&lt;/p&gt;

&lt;h3&gt;
  
  
  🛠️ What does each step involve?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;on: pull_request&lt;/strong&gt;&lt;br&gt;
This section indicates that the workflow will run every time a pull request is opened, updated, or reopened. It is the most common trigger in CI flows for collaborative teams.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;uses: actions/checkout@v4&lt;/strong&gt;&lt;br&gt;
This step downloads the code from the repository so that it is available in the runner.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📌 &lt;em&gt;Tip: You can configure this step to make a shallow clone or bring in specific branches, but the default configuration is usually sufficient.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;uses: actions/setup-node@v4&lt;/strong&gt;&lt;br&gt;
Here we define the version of Node.js that will be used in the runner (v22 in this case). This ensures consistency between developers and CI.&lt;/p&gt;

&lt;p&gt;Some additional useful options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cache: ‘npm’: speeds up the installation of dependencies&lt;/li&gt;
&lt;li&gt;check-latest: true: forces the latest available version of semver&lt;/li&gt;
&lt;li&gt;registry-url: useful if you are going to publish packages to NPM&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;run: npm install&lt;/strong&gt;&lt;br&gt;
Install the project dependencies. For CI environments, it is recommended to use &lt;code&gt;npm ci&lt;/code&gt; if you have a &lt;code&gt;package-lock.json&lt;/code&gt;, as it is faster and more predictable.&lt;/p&gt;

&lt;h3&gt;
  
  
  ⚙️ The specific logic of NX
&lt;/h3&gt;

&lt;p&gt;The most interesting thing about this workflow is that it uses the &lt;code&gt;nx affected&lt;/code&gt; command, which allows you to run tasks only on projects affected by the changes introduced in the pull request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;npx nx affected --target=lint&lt;/strong&gt;&lt;br&gt;
Run linter only on modified projects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;npx nx affected --target=test&lt;/strong&gt;&lt;br&gt;
Run the corresponding tests only on those projects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;npx nx affected --target=build&lt;/strong&gt;&lt;br&gt;
Only compile the packages or applications that have been affected.&lt;/p&gt;

&lt;p&gt;This selective approach is one of the great advantages of NX, and its integration with GitHub Actions makes it especially powerful in large monorepos.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧠 What do --head and --base mean?
&lt;/h3&gt;

&lt;p&gt;These two options tell NX which branches to compare the changes against to determine what has been affected:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;--base=origin/main:&lt;/strong&gt; specifies the reference branch (e.g., main)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;--head=HEAD:&lt;/strong&gt; refers to the current commit of the PR&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;NX will calculate which projects have been modified between main and the HEAD of the pull request, and will only execute the necessary tasks on them.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Final result: Intelligent and efficient CI
&lt;/h3&gt;

&lt;p&gt;This workflow allows each pull request to go through a well-defined validation system, without the need to run unnecessary tasks across the entire repository.&lt;/p&gt;

&lt;p&gt;Key advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Saves execution time in CI&lt;/li&gt;
&lt;li&gt;Less resource consumption&lt;/li&gt;
&lt;li&gt;Early validation of errors in critical code&lt;/li&gt;
&lt;li&gt;Improves the experience for external contributors&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  💡 Ideas for extending this workflow
&lt;/h3&gt;

&lt;p&gt;Some ideas to improve it even further:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add caching with actions/cache&lt;/li&gt;
&lt;li&gt;Run validation on multiple versions of Node using matrix&lt;/li&gt;
&lt;li&gt;Include automatic comments in the pull request with results&lt;/li&gt;
&lt;li&gt;Split jobs in parallel (lint, test, build)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But we'll leave that for another article! 😉&lt;/p&gt;

&lt;h3&gt;
  
  
  🐙 Would you prefer a visual way to build this workflow?
&lt;/h3&gt;

&lt;p&gt;If you don't want to write this YAML by hand or prefer to focus on logic rather than syntax, you can use OctoLab:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Step-by-step visual editor&lt;/li&gt;
&lt;li&gt;✅ Smart fields for NX actions&lt;/li&gt;
&lt;li&gt;✅ Real-time YAML preview&lt;/li&gt;
&lt;li&gt;✅ Automatic validations&lt;/li&gt;
&lt;li&gt;✅ Copy, download, and use instantly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 Try it out at: &lt;a href="https://www.octolab.app" rel="noopener noreferrer"&gt;https://www.octolab.app&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🧵 Conclusion
&lt;/h3&gt;

&lt;p&gt;Well-managed NX monorepos require efficient automation, and this workflow is an excellent way to ensure quality without wasting resources. With tools like GitHub Actions and approaches like &lt;code&gt;nx affected&lt;/code&gt;, you can take your project's CI to the next level.&lt;/p&gt;

&lt;p&gt;And if you want to do all this without fighting with YAML, you know where to find help 🤗.&lt;/p&gt;

</description>
      <category>githubactions</category>
      <category>devops</category>
      <category>cicd</category>
      <category>nx</category>
    </item>
    <item>
      <title>Verify your Pull Requests with GitHub Actions in Node.js projects</title>
      <dc:creator>OctoLab Team</dc:creator>
      <pubDate>Tue, 05 Aug 2025 07:16:08 +0000</pubDate>
      <link>https://forem.com/octolab/verify-your-pull-requests-with-github-actions-in-nodejs-projects-5fdk</link>
      <guid>https://forem.com/octolab/verify-your-pull-requests-with-github-actions-in-nodejs-projects-5fdk</guid>
      <description>&lt;p&gt;One of the most common uses of GitHub Actions in Node.js projects is to automate code validation every time someone proposes a change via a pull request.&lt;/p&gt;

&lt;p&gt;This type of validation usually involves several key steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Install dependencies&lt;/strong&gt; to make sure the project can run correctly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Running the linter&lt;/strong&gt;, a tool that analyzes the style and quality of the code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run the tests&lt;/strong&gt; that automatically verify that the project's functionality continues to work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build the project&lt;/strong&gt; to check for errors before deploying or publishing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this article we will set up a GitHub Actions workflow that automates this whole process every time someone opens or updates a pull request. We will explain step by step what each part of the workflow does and why it is important.&lt;/p&gt;

&lt;h3&gt;
  
  
  🎯 The purpose of the workflow
&lt;/h3&gt;

&lt;p&gt;We want that, every time a pull request is opened in our project, a set of tasks is executed to verify that the code complies with the project standards:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It installs correctly&lt;/li&gt;
&lt;li&gt;Passes the linter tool&lt;/li&gt;
&lt;li&gt;Passes the tests&lt;/li&gt;
&lt;li&gt;Compiles without errors&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🧬 General workflow structure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Node.js pull request verify&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;verify&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Verify&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout code&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Node&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;22"&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run lint&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run lint&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run tests&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run test&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build package&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ⚙️ What parts compose a GitHub Actions workflow?
&lt;/h3&gt;

&lt;p&gt;Before going into detail, it is useful to understand how a GitHub Actions workflow is structured. The main elements are:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trigger (on:)&lt;/strong&gt;&lt;br&gt;
Defines when the workflow is executed. It can be when pushing, opening a pull request, publishing a release, executing manually, etc.&lt;br&gt;
In our case, we use &lt;em&gt;pull_request&lt;/em&gt;, which is triggered every time a PR is created or updated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Job (jobs:)&lt;/strong&gt;&lt;br&gt;
Each workflow can have one or several jobs. A job is a set of tasks that are executed in the same environment.&lt;br&gt;
All the steps of a job share the same filesystem and context. In our example, we have a single job called &lt;em&gt;verify&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Runner (runs-on:)&lt;/strong&gt;&lt;br&gt;
It is the operating system where the job is executed. GitHub provides hosted runners, such as &lt;em&gt;ubuntu-latest&lt;/em&gt;, &lt;em&gt;windows-latest&lt;/em&gt; or &lt;em&gt;macos-latest&lt;/em&gt;, but we also have the possibility to use &lt;em&gt;self-hosted runners&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Steps (steps:)&lt;/strong&gt;&lt;br&gt;
These are the actions or commands that are executed within a job. They can be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reusable actions such as &lt;em&gt;actions/checkout&lt;/em&gt; or &lt;em&gt;actions/setup-node&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Specific commands defined with &lt;em&gt;run&lt;/em&gt;, such as &lt;em&gt;npm install&lt;/em&gt; or &lt;em&gt;npm test&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  🪜 Step-by-step of our workflow
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;
&lt;h4&gt;
  
  
  on: pull_request
&lt;/h4&gt;

&lt;p&gt;This block indicates that the workflow will be triggered when a pull request is opened, updated or reopened in the repository. It is ideal for branch-based continuous integration flows.&lt;/p&gt;
&lt;h4&gt;
  
  
  uses: actions/checkout@v4
&lt;/h4&gt;

&lt;p&gt;This step downloads the code from the repository so that it is available within the runtime environment.&lt;/p&gt;

&lt;p&gt;Some additional options that this action allows are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;fetch-depth: 0&lt;/strong&gt; clones the entire repository history (by default only the current commit).&lt;/li&gt;
&lt;li&gt;ref: branch-name** you can set a specific branch&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;path: subdirectory&lt;/strong&gt; clone the code in a specific path&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For this case, just use it without extra configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  uses: actions/setup-node@v4
&lt;/h4&gt;

&lt;p&gt;This action installs a specific version of Node.js, in our case version 22. It also allows you to configure dependency caching, authentication with registries, and more.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;22"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other useful options are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;cache: ‘npm’&lt;/strong&gt; enables dependency caching using &lt;em&gt;actions/cache&lt;/em&gt; underneath&lt;/li&gt;
&lt;li&gt;check-latest: true** forces to use the latest available version that complies with the &lt;em&gt;semver&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;registry-url:&lt;/strong&gt; to configure publishing to NPM&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Working scripts
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run lint&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run test&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These steps execute the commands defined in the project's &lt;em&gt;package.json&lt;/em&gt; file. Their purpose is to prepare and validate the code before it goes to production:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;npm install&lt;/strong&gt; will install all the project's dependencies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;npm run lint&lt;/strong&gt; will run the linter, which helps to detect style errors or common problems in the code.&lt;/li&gt;
&lt;li&gt;npm run test** will run the automatic tests defined by the team.&lt;/li&gt;
&lt;li&gt;npm run build** will generate the final package, either an app, a library or a bundle ready to deploy.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 If you are using &lt;em&gt;package-lock.json&lt;/em&gt;, you can replace &lt;em&gt;npm install&lt;/em&gt; with &lt;em&gt;npm ci&lt;/em&gt;, which is faster and guarantees a more consistent and reproducible installation in CI environments.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  ✅ Final result
&lt;/h3&gt;

&lt;p&gt;With this flow you guarantee that all code proposed via pull request has gone through a basic verification, without the need for manual reviews or local builds. You can integrate it with other additional steps such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Static analysis (Sonar, extended ESLint...).&lt;/li&gt;
&lt;li&gt;Automatic comments on Pull Request&lt;/li&gt;
&lt;li&gt;Deploys to staging environments&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🐙 Do you want to avoid writing it by hand? There is a more convenient way
&lt;/h3&gt;

&lt;p&gt;Understanding how a workflow works in Github Actions is indispensable. It gives you control and helps you customize everything to your needs.&lt;/p&gt;

&lt;p&gt;Now... if you don't feel like struggling with the syntax, that's fine too.&lt;br&gt;
At &lt;a href="https://www.octolab.app" rel="noopener noreferrer"&gt;OctoLab&lt;/a&gt; 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.&lt;/p&gt;

&lt;p&gt;✅ Without indentation errors&lt;br&gt;
✅ With built-in validations&lt;br&gt;
✅ Copy, paste and go.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧠 Conclusion
&lt;/h3&gt;

&lt;p&gt;This workflow is an excellent basis for quality assurance in Node.js projects. It can be easily adapted to other needs: monorepos, automatic deployments, publishing to NPM or running on multiple versions of Node.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you prefer to use &lt;a href="https://www.octolab.app" rel="noopener noreferrer"&gt;OctoLab&lt;/a&gt; we will be very grateful for your feedback! 🤗&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>githubactions</category>
      <category>devops</category>
      <category>cicd</category>
      <category>node</category>
    </item>
  </channel>
</rss>
