<?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: Gina Beki</title>
    <description>The latest articles on Forem by Gina Beki (@gina).</description>
    <link>https://forem.com/gina</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%2F1088904%2Fa1485f8a-048b-4f6b-8571-dc5f0b7ed49b.jpeg</url>
      <title>Forem: Gina Beki</title>
      <link>https://forem.com/gina</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/gina"/>
    <language>en</language>
    <item>
      <title>Automating Your Project Deployment with GitHub Actions: A Step-by-Step Guide</title>
      <dc:creator>Gina Beki</dc:creator>
      <pubDate>Tue, 26 Nov 2024 15:28:29 +0000</pubDate>
      <link>https://forem.com/gina/automating-your-project-deployment-with-github-actions-a-step-by-step-guide-14bn</link>
      <guid>https://forem.com/gina/automating-your-project-deployment-with-github-actions-a-step-by-step-guide-14bn</guid>
      <description>&lt;p&gt;As developers, we often spend hours repeatedly performing the same deployment tasks. Have you ever asked yourself how much time you could save if you could automate this process? In this article, I’ll walk you through implementing a CI/CD pipeline using GitHub Actions, demonstrated with a practical example project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding CI/CD in Modern Development
&lt;/h2&gt;

&lt;p&gt;Think of CI/CD as your personal development assistant: First, it checks your code for any issues through automated tests and quality checks (that’s the CI part). Once everything looks good, it handles the deployment process automatically (that’s the CD part) — from security checks to the final deployment on Vercel or whatever deployment platform of your choice. It’s like having a code reviewer who ensures every code change is perfect before it goes live! 🚀&lt;/p&gt;

&lt;p&gt;Let’s break down what each part does:&lt;/p&gt;

&lt;h3&gt;
  
  
  Continuous Integration (CI)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Automatically runs tests when you push code&lt;/li&gt;
&lt;li&gt;Checks your code quality and style&lt;/li&gt;
&lt;li&gt;Makes sure your code works well with existing features&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Helps catch problems early before they reach production&lt;/p&gt;
&lt;h3&gt;
  
  
  Continuous Deployment (CD)
&lt;/h3&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Automatically deploys your tested code&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ensures your app is always ready to go live&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Handles all the deployment steps for you&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Gets your changes to users quickly and safely&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Implementation Guide
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Prerequisites
&lt;/h4&gt;

&lt;p&gt;Before we begin, make sure you have the following installed on your machine:-&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node.js(v18 or higher)&lt;/li&gt;
&lt;li&gt;npm(comes with Node.js)&lt;/li&gt;
&lt;li&gt;Git&lt;/li&gt;
&lt;li&gt;GitHub account&lt;/li&gt;
&lt;li&gt;Vercel account (free tier is fine)&lt;/li&gt;
&lt;li&gt;Your favorite code editor (I’m using VS Code)
Project Setup&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  1. Install Dependencies and setting up package.json
&lt;/h3&gt;

&lt;p&gt;Before we start implementing, let’s understand how our project is organized. I will guide you in creating a project that demonstrates GitHub Actions automation:&lt;/p&gt;

&lt;p&gt;First, let’s create a repo on &lt;strong&gt;GitHub&lt;/strong&gt; called automation-demo-project (or name it anything of your preference). Clone it to your local machine and cd into the project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone [your-repo-url]
cd automation-demo-project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Initialize the project using npm by running this command:-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm init -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will generate a package.json file:-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "name": "",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" &amp;amp;&amp;amp; exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run this command to install the dev dependencies that we will be using:-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install --save-dev eslint jest nodemon supertest

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;eslint:&lt;/strong&gt; Helps maintain code quality by checking our code for potential errors and enforcing consistent coding styles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;jest:&lt;/strong&gt; A JavaScript testing framework that makes it easy to write and run tests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;nodemon:&lt;/strong&gt; Automatically restarts our application when file changes are detected.&lt;/li&gt;
&lt;li&gt;**supertest: **Provides a high-level abstraction for testing HTTP requests, perfect for testing our Express.js API
Then, install Express by running this command:-
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install express

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;**express: **a Node.js web framework that helps to create server and API endpoints easily&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After installing the dependencies, let’s create a .gitignore file in the root of our project to tell Git which files and directories (like node_modules) shouldn’t be tracked or uploaded to our repository — this helps keep our repository clean and prevents unnecessary files from being committed. Add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node_modules/
.secrets
.vercel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is what our package.json looks like so far:-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "name": "automation-demo-project",
  "version": "1.0.0",
  "description": "Demo project for GitHub Actions",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" &amp;amp;&amp;amp; exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "dotenv": "^16.4.5",
    "express": "^4.17.1"
  },
  "devDependencies": {
    "eslint": "^8.42.0",
    "jest": "^29.7.0",
    "nodemon": "^3.0.0",
    "supertest": "^6.3.4"
  }
}

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

&lt;/div&gt;



&lt;p&gt;Let’s add scripts to our package.json to manage various tasks in our project. Update the scripts section as follows:-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"scripts": {
    "start": "node index.js",
    "dev": "nodemon index.js",
    "test": "jest",
    "test:coverage": "jest --coverage",
    "lint": "eslint .",
    "lint:fix": "eslint . --fix"
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These scripts allow us to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;npm start:&lt;/strong&gt; Launch the server&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;npm run dev:&lt;/strong&gt; Run in development mode with auto-reload&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;npm test:&lt;/strong&gt; Run tests&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;npm run test:coverage:&lt;/strong&gt; Generate test coverage report&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;npm run lint:&lt;/strong&gt; Check code quality&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;npm run lint:fix:&lt;/strong&gt; Automatically fix code style issues&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your complete package.json should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "name": "automation-demo-project",
  "version": "1.0.0",
  "description": "Demo project for GitHub Actions",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "dev": "nodemon index.js",
    "test": "jest",
    "test:coverage": "jest --coverage",
    "lint": "eslint .",
    "lint:fix": "eslint . --fix"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "dotenv": "^16.4.5",
    "express": "^4.17.1"
  },
  "devDependencies": {
    "eslint": "^8.42.0",
    "jest": "^29.7.0",
    "nodemon": "^3.0.0",
    "supertest": "^6.3.4"
  }
}

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

&lt;/div&gt;



&lt;p&gt;This should be the initial structure after installing all the above dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;automation-demo-project/
├── package.json
├── package-lock.json
├── .gitignore
└── node_modules/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let’s create a .eslintrc.js file in the root and add the following code:-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = {
    env: {
      node: true,
      es2021: true,
      jest: true,
      commonjs: true
    },
    extends: ['eslint:recommended'],
    parserOptions: {
      ecmaVersion: 2021
    },
    globals: {
      process: true
    },
    rules: {
      'indent': ['error', 2],
      'linebreak-style': ['error', 'unix'],
      'quotes': ['error', 'single'],
      'semi': ['error', 'always'],
      'no-unused-vars': 'warn',
      'no-console': 'warn'
    }
  };

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

&lt;/div&gt;



&lt;p&gt;Then, create eslint.config.mjs, and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import globals from 'globals';
import pluginJs from '@eslint/js';

/** @type {import('eslint').Linter.Config[]} */
export default [
  {
    files: ['**/*.js'],
    languageOptions: {
      sourceType: 'commonjs',
      globals: globals.node,
    },
  },
  {
    files: ['**/*.test.js'],
    languageOptions: {
      globals: globals.jest,
    },
  },
  pluginJs.configs.recommended,
];

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

&lt;/div&gt;



&lt;p&gt;Up to this point, this is the folder structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;automation-demo-project/
├── .gitignore
├──eslint.config.mjs
├── package.json
├── package-lock.json
├── .eslintrc.js
└── node_modules/

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

&lt;/div&gt;



&lt;p&gt;Create a folder named test in the root. Create &lt;strong&gt;index.test.js&lt;/strong&gt; file in the test folder, and add the following code that will be used to test the code in index.js that we will be creating next:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const request = require('supertest');
const app = require('../index');

describe('API Tests', () =&amp;gt; {
  test('GET / should return hello message', async () =&amp;gt; {
    const response = await request(app).get('/');
    expect(response.body.message).toBe('Hello Github Actions!');
    expect(response.statusCode).toBe(200);
  });
});

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

&lt;/div&gt;



&lt;p&gt;Next, let’s create a file in the root called index.js, which will have a simple Express server that returns a “Hello” message — we’ll use it to demonstrate how GitHub Actions can automatically test and deploy our code whenever we make changes&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require('express');
const app = express();

app.get('/', (req, res) =&amp;gt; {
  res.json({ message: 'Hello Github Actions!' });
});

module.exports = app;

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

&lt;/div&gt;



&lt;p&gt;After creating index.js, this is our updated folder structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;automation-demo-project/
├.gitignore
├test/
       └── index.test
├package.json
├package-lock.json
├.eslintrc.js
├index.js
├eslint.config.mjs
├node_modules/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Implementing CI Pipeline
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;automation-demo-project/
├.github/
           └── workflows/
                   └── main.yml  
├test/
       └── index.test
├package.json
├package-lock.json
├.eslintrc.js
├index.js
├.gitignore
├eslint.config.mjs
├node_modules/

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

&lt;/div&gt;



&lt;p&gt;The Continuous Integration (CI) phase automatically validates our code through testing, linting, and quality checks, then builds our application by installing dependencies and optimizing assets. Once CI passes, the Continuous Deployment (CD) phase takes over. Inside main.yml, add the code below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
  workflow_dispatch:

jobs:
  build-and-test:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [18.x, 20.x]

    steps:
      # Checks-out your repository under $GITHUB_WORKSPACE
      - uses: actions/checkout@v4

      # Setup Node.js environment
      - name: Setup Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: "npm" # Caches npm dependencies

      # Install dependencies
      - name: Install Dependencies
        run: npm ci # Uses clean install, preferred in CI environments

      # Check for lint errors
      - name: Run ESLint
        run: npm run lint

      # Run tests
      - name: Run Tests
        run: npm test

      # Optional: Add test coverage reporting
      - name: Generate Test Coverage
        run: npm run test -- --coverage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Setting Up CD with Vercel
&lt;/h3&gt;

&lt;p&gt;Next, we’ll add a deploy.yml file alongside our CI configuration in the .github/workflows directory. This file handles our automated deployment process to Vercel. Our complete workflow structure looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;automation-demo-project/
├.github/
           └── workflows/
                   └── main.yml  
                   └── deploy.yml  
├test/
       └── index.test
├package.json
├package-lock.json
├.eslintrc.js
├index.js
├.gitignore
├eslint.config.mjs
├node_modules/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Continuous Deployment (CD) automates our deployment process to Vercel. Here’s how our workflow handles it inside deploy.yml:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Deploy to Vercel

on:
  push:
    branches: [main]
  workflow_dispatch:

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      # Check only required secrets for personal account
      - name: Check Required Secrets
        run: |
          if [ -z "${{ secrets.VERCEL_TOKEN }}" ]; then
            echo "Error: VERCEL_TOKEN is not set"
            exit 1
          fi

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "20.x"
          cache: "npm"

      - name: Install Dependencies
        run: npm ci

      - name: Build
        run: npm run build --if-present

      # Simplified Vercel deployment for personal accounts
      - name: Deploy to Vercel
        run: |
          npx vercel --token ${{ secrets.VERCEL_TOKEN }} --prod --yes

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setting up Vercel Tokens and GitHub Secrets
&lt;/h3&gt;

&lt;p&gt;Commit and push all your changes to GitHub, and deploy your project on Vercel, here’s a detailed guide on how to deploy a project on Vercel.&lt;/p&gt;

&lt;p&gt;If you check your GitHub Actions tab now, you’ll notice red ❌ failing checks — this is expected! The deployment is failing because we haven’t set up our Vercel token yet. We’ll fix this in the next step when we configure our GitHub secrets.&lt;/p&gt;

&lt;p&gt;Now let’s create this file vercel.json in the root and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "version": 2,
    "builds": [
      {
        "src": "index.js",
        "use": "@vercel/node"
      }
    ],
    "routes": [
      {
        "src": "/(.*)",
        "dest": "index.js"
      }
    ]
  }

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

&lt;/div&gt;



&lt;p&gt;The vercel.json file configures how our application runs on Vercel: it specifies version 2 of Vercel’s build system, tells Vercel to use Node.js runtime for our index.js file, and sets up routing so that all incoming requests are properly directed to our Express application — think of it as a roadmap that guides Vercel on how to serve our API.&lt;/p&gt;

&lt;p&gt;Before our deployment workflow can run successfully, we need to configure our Vercel tokens and add them to GitHub secrets. Here’s how:&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Get Your Vercel Token:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Go to vercel token&lt;/li&gt;
&lt;li&gt;Click “Create Token” — Give it a name (e.g “Vercel_Token”), scope(choose the project under where your project is running), and expiration( e.g I chose 90 days, pick one that works for your project)&lt;/li&gt;
&lt;li&gt;Copy the token (you won’t see it again!)&lt;/li&gt;
&lt;li&gt;In the root of your project create a .secrets file and paste the token you’ve created as shown below:-
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;VERCEL_TOKEN=paste your token here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The file structure should reflect this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;automation-demo-project/
├.github/
           └── workflows/
                   └── main.yml  
                   └── deploy.yml  
├test/
       └── index.test
├package.json
├package-lock.json
├.eslintrc.js
├index.js
├.gitignore
├.secrets
├eslint.config.mjs
├vercel.json
├node_modules/

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

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Add Token to GitHub Secrets:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Go to your GitHub repository&lt;/li&gt;
&lt;li&gt;Click Settings → Secrets and Variables → Actions&lt;/li&gt;
&lt;li&gt;Click “New repository secret”&lt;/li&gt;
&lt;li&gt;Name: VERCEL_TOKEN&lt;/li&gt;
&lt;li&gt;Value: Paste your Vercel token&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s understand each part of our deployment workflow:&lt;/p&gt;

&lt;h4&gt;
  
  
  Workflow Triggers
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;name: Deploy to Vercel — Identifies our workflow in the GitHub Actions dashboard&lt;/li&gt;
&lt;li&gt;on: push: branches: [main] — Runs when code is pushed to the main branch&lt;/li&gt;
&lt;li&gt;workflow_dispatch — Allows manual workflow trigger from GitHub UI&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Job Configuration
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;runs-on: ubuntu-latest — Uses Ubuntu for running our deployment&lt;/li&gt;
&lt;li&gt;steps — List of tasks our workflow will perform&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Key Steps Explained
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;actions/checkout@v4 — Gets our repository code&lt;/li&gt;
&lt;li&gt;Check Required Secrets — Verifies Vercel token is set&lt;/li&gt;
&lt;li&gt;Setup Node.js — Prepares Node.js environment&lt;/li&gt;
&lt;li&gt;Install Dependencies — Get project dependencies&lt;/li&gt;
&lt;li&gt;Build — Build project if needed&lt;/li&gt;
&lt;li&gt;Deploy to Vercel — Deploys to Vercel using our token&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This workflow ensures our code is properly prepared and securely deployed whenever we push changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Successful Implementation
&lt;/h3&gt;

&lt;p&gt;Let’s verify our implementation step by step:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Local Testing
&lt;/h3&gt;

&lt;p&gt;First, let’s run our tests locally to ensure everything works as expected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run test &amp;amp;&amp;amp; npm run lint

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

&lt;/div&gt;



&lt;p&gt;If the run is successful, this should be the output:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbmosl18lvpzm9va5a83b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbmosl18lvpzm9va5a83b.png" alt="Image description" width="514" height="257"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. GitHub Actions Dashboard
&lt;/h3&gt;

&lt;p&gt;Commit all your changes and push to the main branch to see it in action&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkl98dcde5bz5b01xrlh6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkl98dcde5bz5b01xrlh6.png" alt="Image description" width="720" height="295"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Upon a successful run, you should see a green checkmark with the name of your last commit ✅ Each workflow took only seconds to complete, demonstrating the efficiency of our automated pipeline.&lt;/p&gt;

&lt;p&gt;This workflow automatically deploys our project whenever we push code to our main branch. It checks out our code, sets up Node.js, and deploys to Vercel — all without us having to lift a finger! 🚀 The best part? Our sensitive deployment tokens are safely stored in GitHub secrets, keeping our application secure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;By implementing this automation pipeline, what used to take me 30 minutes of manual deployment now happens in just 2 minutes. I’d love to hear how you’re using GitHub Actions in your projects! Drop a comment below, check out my repository for the complete implementation, or reach out if you need help setting up your own automation pipeline.&lt;/p&gt;

&lt;p&gt;I hope you found this article helpful, and that you feel confident building your automation pipeline with GitHub Actions.&lt;/p&gt;

&lt;p&gt;You can clone this project here &lt;a href="https://github.com/ginabeki/automation-demo-project" rel="noopener noreferrer"&gt;Automation demo repo&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>githubactions</category>
      <category>cicd</category>
      <category>vercel</category>
    </item>
  </channel>
</rss>
