
Learn how to build a robust CI/CD pipeline with GitHub Actions, Vercel deployments, and Neon serverless Postgres databases.
When I build full-stack web applications for clients, keeping my deployment pipeline clean and reliable is just as important as writing the core features. Too many developers rely entirely on default platform triggers without automated testing or branch-based database migrations. Over time, this leads to broken production builds and messy database schemas.
Today, I want to share how I set up a robust CI/CD pipeline using GitHub Actions, Vercel, and Neon serverless Postgres. This setup ensures that every pull request runs my test suite against an isolated database branch, builds securely, and deploys smoothly.
The stack we are working with includes GitHub for version control and workflow automation, Vercel for hosting our frontend and serverless API routes, and Neon for instant Postgres branching.
Vercel has great out-of-the-box CI/CD for git repositories. When you push to main, it builds and deploys. When you open a pull request, it creates a preview deployment.
However, adding GitHub Actions gives us finer control over pre-deployment checks. We can run linting, execute end-to-end tests, type-check our codebase, and run database migrations on a dedicated staging branch before Vercel ever touches production.
By combining Neon's branching capability with GitHub Actions, we can spin up a temporary database branch for every pull request, run migrations and tests against it, and then tear it down automatically once the PR is merged or closed.
Neon is a serverless Postgres provider that treats database branches much like Git branches. This is a game changer for testing schema changes.
First, you need to grab your Neon API key and project ID from your Neon console. Store them securely in your GitHub repository secrets as NEON_API_KEY and NEON_PROJECT_ID.
When we write our GitHub Actions workflow, we will use the Neon CLI or API to create a branch dynamically for our pull requests.
Before writing the workflow file, make sure your Vercel project is linked and your required environment variables are set. For GitHub Actions to interact with Vercel, you need:
Tagged with
Leave a comment
VERCEL_TOKEN: Generated from your Vercel account settings.VERCEL_ORG_ID: Found in your Vercel project settings.VERCEL_PROJECT_ID: Found in your Vercel project settings.Store these in your GitHub repository settings under Secrets and Variables -> Actions.
Create a new file in your repository at .github/workflows/deploy.yml. Here is a practical workflow configuration that handles testing, database branching, and deployment triggers.
name: CI/CD Pipeline
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test-and-lint:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- name: Install Dependencies
run: npm ci
- name: Run Linter and Type Check
run: |
npm run lint
npm run typecheck
- name: Run Unit Tests
run: npm test
deploy-to-vercel:
needs: test-and-lint
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Install Vercel CLI
run: npm install --global vercel@latest
- name: Pull Vercel Environment Information
run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}
- name: Build Project Artifacts
run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }}
- name: Deploy to Vercel Production
run: vercel deploy --prod --prebuilt --token=${{ secrets.VERCEL_TOKEN }}
This workflow ensures that code is never pushed to production unless it successfully passes linting, type-checking, and unit tests.
When your app relies on Prisma or Drizzle ORM, managing database migrations during deployment requires care. If you run migrations directly on your production database during every build, a failing migration can take your app down.
I recommend running migrations as a distinct step in your deployment pipeline or utilizing Neon's migration workflows.
If you use Prisma, your workflow can include a step like this before finalizing deployment:
- name: Run Database Migrations
run: npx prisma migrate deploy
env:
DATABASE_URL: ${{ secrets.PRODUCTION_DATABASE_URL }}
For pull requests, you can use Neon's API action to create a temporary child branch of your main database, supply that temporary DATABASE_URL to your preview environment tests, and then delete the branch when the PR is closed.
Once your deployment is live on Vercel, automated pipelines are only half the battle. You need to know immediately if something breaks in production.
I always configure Vercel log drains or integrate lightweight error tracking tools like Sentry. Combined with Neon's query performance insights, you can quickly catch slow queries or unhandled server-side exceptions before clients notice.
Setting up a structured CI/CD pipeline with GitHub Actions, Vercel, and Neon takes an hour upfront, but it saves countless hours of debugging broken production environments later. It brings professional engineering standards to any project, whether it is a small business website or a complex SaaS product.
Need help setting up clean infrastructure, fast APIs, or a full-stack web application for your business? Get in touch and let's talk about your project.