DEV Community

Cover image for A Practical Guide to Deploying Frontend Apps on Vercel Using GitHub Actions
EphraimX
EphraimX

Posted on

A Practical Guide to Deploying Frontend Apps on Vercel Using GitHub Actions

Deploying frontend applications quickly and reliably is essential for fast iteration and consistent user experience. While Vercel is known for its seamless integration with Git-based workflows, setting up a custom CI/CD pipeline using GitHub Actions gives you more control over how and when deployments are triggered.

In this article, you'll learn how to deploy a frontend application to Vercel using GitHub Actions. This setup allows you to define your own deployment logic, automate builds, and push updates without relying on Vercel’s default Git integrations.

We’ll walk through everything from cloning the project to configuring GitHub Actions to deploy changes automatically. By the end of this guide, you'll have a custom, production-ready CI/CD pipeline tailored to your frontend application's needs.

Why Not Just Use Vercel’s Default Git Integration?

While Vercel's built-in Git integration is convenient, it lacks the flexibility needed for more complex workflows. Using GitHub Actions gives you full control over your CI/CD pipeline—ideal for monorepos, multi-step build/test logic, or when you need conditional deployment rules that Vercel's default setup doesn't support.

Prerequisites

Before diving into the deployment setup, make sure you meet the following requirements:

  • A TypeScript-based frontend application that is production-ready. If you don’t already have one, you can clone the example project used in this guide and follow along.
  • A GitHub repository where your frontend code resides. If you're cloning the example repo, push it to a new GitHub repository of your own.
  • A Vercel account with a project already created. You’ll need your Vercel Project ID and a Vercel Personal Access Token, which we’ll use later when configuring the GitHub Actions workflow.
  • Node.js and npm installed in your development environment, primarily for local testing. The deployment workflow will handle installation in the CI environment.

Table of Contents

  1. Cloning the Repository
  2. Understanding the Frontend Application
  3. GitHub Actions Workflow for Deploying to Vercel
  4. Obtaining Your Vercel Token
  5. Adding the Vercel Token to GitHub Secrets
  6. Deploying and Testing the Application
  7. Conclusion

Cloning the Repository

To follow along with this guide, you can use the sample project hosted at the GitHub repository below. The frontend application is located in the frontend directory.

git clone https://github.com/EphraimX/blbjzl-ai-accountability-application-github-actions.git
cd blbjzl-ai-accountability-application-github-actions/frontend
Enter fullscreen mode Exit fullscreen mode

The frontend is a TypeScript-based application designed to interact with an AI-powered backend for user accountability.

Understanding the Frontend Application

Frontend Application Interface

The core of the frontend application is located in the Chat.tsx file under the /frontend/src/Component/ directory. This component handles the interactive chat interface between the user and the AI accountability bot. Here’s a breakdown of the key sections in the code:

1. State Management:

The messages state holds an array of chat messages between the user and the bot. Initially, the bot sends a welcome message to start the conversation.

const [messages, setMessages] = useState<IMessage[]>([
  { sender: 'bot', content: 'Hey there! I’m BLBJZL, your personal accountability partner AI. I’m here to keep you on track, motivated, and moving toward your goals—no judgment, just solid support. Ready to tackle your to-do list together? Let’s do this. What’s first on the agenda?' },
]);
Enter fullscreen mode Exit fullscreen mode

The input state holds the current value of the user’s message input.

const [input, setInput] = useState('');
Enter fullscreen mode Exit fullscreen mode

2. Message Structure:

The chat messages are structured as an array of objects, each containing a sender (either 'user' or 'bot') and the content of the message. The IMessage interface is defined as follows:

interface IMessage {
  sender: 'user' | 'bot';
  content: string;
}
Enter fullscreen mode Exit fullscreen mode

3. Sending Messages:

When the user types a message and presses send, the sendMessage function is triggered. This function sends the user’s input to the backend via a POST request to the /chat endpoint.

const sendMessage = async () => {
  if (input.trim()) {
    const newUserMessage: IMessage = { sender: 'user', content: input };
    setMessages((prevMessages) => [...prevMessages, newUserMessage]);

    try {
      const response = await fetch('https://blbjzl-accountability-application-backend.fly.dev/chat', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ user_input: input }),
      });

      if (!response.ok) {
        throw new Error(`HTTP error! Status: ${response.status}`);
      }

      const data = await response.json();
      const newBotMessage: IMessage = { sender: 'bot', content: data.reply };
      setMessages((prevMessages) => [...prevMessages, newBotMessage]);
    } catch (error) {
      console.error('Error sending message:', error);
      setMessages((prevMessages) => [...prevMessages, { sender: 'bot', content: 'Uh-oh, looks like the server’s not responding right now. No stress—we’ve got this. Give it another try, and if it still doesn’t work, we’ll troubleshoot it together. One step at a time!' }]);
    }

    setInput('');
  }
};
Enter fullscreen mode Exit fullscreen mode

4. Rendering the UI:

The component maps over the messages array and displays each message in the chat window. Depending on the message sender, different icons (user or bot) are displayed alongside the message content.

<div className="chat-container">
  {messages.map((message, index) => (
    <div key={index} className={`message ${message.sender}`}>
      {message.sender === 'user' ? (
        <FontAwesomeIcon icon={faUser} className="icon" />
      ) : (
        <FontAwesomeIcon icon={faRobot} className="icon" />
      )}
      <div className="message-content">{message.content}</div>
    </div>
  ))}
</div>
Enter fullscreen mode Exit fullscreen mode

The ChatInput component is used for the user to type their messages. Here's how the input section is rendered:

<ChatInput value={input} onChange={(e) => setInput(e.target.value)} onSend={sendMessage} />
Enter fullscreen mode Exit fullscreen mode

The ChatInput component itself is defined as follows:

const ChatInput: React.FC<ChatInputProps> = ({ value, onChange, onSend }) => {
  return (
    <div className="send-container">
      <input
        type="text"
        value={value}
        onChange={onChange}
        placeholder="Typing"
        onKeyPress={(e) => e.key === 'Enter' && onSend()}
      />
      <button type="button" onClick={onSend}>I’m Listening</button>
    </div>
  );
};

Enter fullscreen mode Exit fullscreen mode

This component provides an input field for the user to type their messages and a button to send them. The user can either click the button or press "Enter" to trigger the onSend function, which initiates the process of sending the user's message and receiving a response from the backend.

GitHub Actions Workflow for Deploying to Vercel

To automate deployments to Vercel whenever updates are pushed to the frontend/ directory on the main branch, create a workflow file at:
.github/workflows/frontend-vercel-deploy.yml

The following workflow uses Node.js to install dependencies, build the project, and then deploy it to Vercel using the Vercel CLI:

GitHub Actions Workflow File:

name: Github Actions Client Deployment To Vercel

on:
  push:
    paths:
      - 'frontend/**'
    branches:
      - main

jobs:
  deploy-client-to-vercel:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repository
        uses: actions/checkout@v2

      - name: Setup NodeJS
        uses: actions/setup-node@v2
        with:
          node-version: '23'

      - name: Install Dependencies
        working-directory: ./frontend
        run: npm install

      - name: Build Project
        working-directory: ./frontend
        run: npm run build

      - name: Deploy to Vercel
        env:
          VERCEL_TOKEN: ${{secrets.VERCEL_TOKEN}}
        run: npx vercel --prod --token $VERCEL_TOKEN --yes --cwd frontend
Enter fullscreen mode Exit fullscreen mode

Explanation of the Workflow Steps:

  1. on.push: This specifies that the workflow will trigger whenever there are changes pushed to the frontend/ directory on the main branch. This ensures that only changes related to the frontend app will trigger the deployment.
  2. jobs.deploy-client-to-vercel: This defines a job called deploy-client-to-vercel, which runs on the ubuntu-latest environment. It contains several steps to install dependencies, build the project, and deploy it to Vercel.
  3. Checkout Repository:
    • This step uses actions/checkout@v2 to clone the repository into the GitHub Actions runner, making all files available for the subsequent steps.
  4. Setup NodeJS:
    • This step ensures that the Node.js environment is set up using actions/setup-node@v2, specifying Node version 23. This is needed for building the frontend app using npm.
  5. Install Dependencies:
    • This step navigates to the frontend directory (working-directory: ./frontend) and runs npm install to install the project’s dependencies defined in package.json.
  6. Build Project:
    • This step builds the project by running npm run build in the frontend directory. This step will prepare the frontend application for deployment by compiling the TypeScript code and optimizing it for production.
  7. Deploy to Vercel:
    • In this final step, the application is deployed to Vercel using the npx vercel command. The VERCEL_TOKEN is passed as an environment variable, which allows GitHub Actions to authenticate with Vercel and trigger the deployment. The --prod flag ensures that the deployment is pushed to the production environment. The --yes flag automatically confirms the deployment without requiring any further input.
    • Important: The VERCEL_TOKEN is stored in GitHub Secrets to ensure that your deployment credentials are kept secure. You will need to generate and store this token in your repository's settings.

Obtaining Your Vercel Token

To deploy your frontend application using GitHub Actions, you'll need a personal access token from Vercel. Follow these steps to generate one:

  1. Sign in to your Vercel dashboard.
  2. Click on your profile image at the top-right corner of the screen.
  3. From the dropdown menu, select Account Settings.
  4. In the left sidebar, navigate to Tokens and click it.
  5. On the Tokens page:
    • Enter a token name.
    • Choose the scope — either assign it to a specific project (recommended for security) or your entire account.
    • Set an expiry date.
    • Click Create to generate the token.

Once created, copy the token immediately — you won't be able to view it again.

You’ll add this token to your GitHub repository as a secret in the next step.

Adding the Vercel Token to GitHub Secrets

Once you’ve generated your Vercel token, you’ll need to store it securely in your GitHub repository to allow the GitHub Actions workflow to access it during deployment. Here’s how to do that:

  1. Go to your repository on GitHub.
  2. Click on the Settings tab (you must have admin access to see this).
  3. In the left sidebar, select Secrets and variables > Actions.
  4. Click the New repository secret button.
  5. Set the Name as VERCEL_TOKEN — this must match the name referenced in your workflow file.
  6. Paste your token into the Secret field.
  7. Click Add secret.

Once saved, GitHub Actions will be able to access this token securely during workflow execution.

Deploying and Testing the Application

With your GitHub Actions workflow in place and your Vercel token securely stored in GitHub Secrets, deployment is triggered automatically on every push to the main branch affecting files in the frontend/ directory.

To deploy:

  1. Make your changes locally and push them to GitHub:
   git add .
   git commit -m "Trigger deployment to Vercel"
   git push origin main
Enter fullscreen mode Exit fullscreen mode
  1. Visit your repository on GitHub and click the Actions tab.
  2. A new workflow run will be listed under Github Actions Client Deployment To Vercel.
  3. Click into it to monitor each stage — from installing dependencies to building and deploying your project to Vercel.

Once the job completes successfully, your frontend app will be available live on the web via the Vercel-provided domain.

What to Expect on Vercel

After deployment, navigate to your Vercel Dashboard. Select your project from the list to access:

Vercel Application

  • Production Deployment Preview: A preview link for your live app.
  • Deployment Status: Confirmation that your GitHub Actions workflow deployed the app successfully.
  • Activity Logs: Timestamped logs of recent deployments and their sources (e.g., GitHub push).
  • Environment Settings: A place to review or update your deployment tokens, domains, and build configuration.

This dashboard serves as your central place for monitoring the health, deployment history, and performance of your frontend application.

Conclusion

Deploying a TypeScript-based frontend application to Vercel using GitHub Actions allows for efficient, automated releases directly from your repository. By structuring the GitHub workflow correctly and managing deployment tokens securely, you eliminate the need for manual deployments and reduce the chances of human error.

This guide walked through the project structure, explained key parts of the application, and set up a CI/CD pipeline that ensures your changes are live as soon as they hit the main branch. It’s a clean, repeatable process that works well for both solo projects and team workflows.

If you found this guide helpful, consider liking the article, connecting with me on LinkedIn, or checking out some of my other projects and writings on my portfolio site.

Top comments (0)