DEV Community

Lucas M Dev
Lucas M Dev

Posted on

GitHub Actions CI/CD for Beginners: Deploy Your App Automatically in 2026

You push code, tests run automatically, and your app deploys itself. That's CI/CD, and GitHub Actions makes it free and surprisingly easy.

What Is CI/CD?

  • CI (Continuous Integration): Automatically run tests when you push code
  • CD (Continuous Deployment): Automatically deploy when tests pass

GitHub Actions gives you 2,000 free minutes/month on public repos (and 500 on private).

Your First Workflow: Run Tests on Every Push

Create .github/workflows/test.yml:

name: Run Tests

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

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

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

      - name: Install dependencies
        run: npm ci

      - name: Run tests
        run: npm test

      - name: Run linter
        run: npm run lint
Enter fullscreen mode Exit fullscreen mode

That's it. Push this file and GitHub will run your tests on every push and PR.

Deploy to Vercel on Merge

name: Deploy to Vercel

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Deploy to Vercel
        uses: amondnet/vercel-action@v25
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
          vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
          vercel-args: '--prod'
Enter fullscreen mode Exit fullscreen mode

Deploy a Docker App to Railway

name: Deploy to Railway

on:
  push:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci && npm test

  deploy:
    needs: test  # Only deploy if tests pass
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install Railway CLI
        run: npm install -g @railway/cli

      - name: Deploy
        run: railway up
        env:
          RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
Enter fullscreen mode Exit fullscreen mode

Useful Workflow Patterns

Matrix Testing (Multiple Node Versions)

strategy:
  matrix:
    node-version: [18, 20, 22]

steps:
  - uses: actions/setup-node@v4
    with:
      node-version: ${{ matrix.node-version }}
Enter fullscreen mode Exit fullscreen mode

Cache Dependencies

- uses: actions/cache@v4
  with:
    path: ~/.npm
    key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
Enter fullscreen mode Exit fullscreen mode

Run Only When Specific Files Change

on:
  push:
    paths:
      - 'src/**'
      - 'package.json'
Enter fullscreen mode Exit fullscreen mode

Scheduled Workflows (Cron)

on:
  schedule:
    - cron: '0 9 * * 1'  # Every Monday at 9 AM UTC
Enter fullscreen mode Exit fullscreen mode

Setting Up Secrets

  1. Go to your repo > Settings > Secrets and variables > Actions
  2. Click "New repository secret"
  3. Add your secret (e.g., VERCEL_TOKEN)

Never put secrets directly in workflow files.

Common Mistakes

  1. Not using npm ci — Use npm ci instead of npm install in CI (it's faster and more deterministic)
  2. Forgetting to cache — Caching node_modules or ~/.npm saves 30-60 seconds per run
  3. Running everything on push — Use path filters to avoid running tests when you only changed docs
  4. Not setting timeout — Add timeout-minutes: 10 to prevent stuck workflows from eating your minutes

My Recommended Starter Setup

For most projects, you need just two workflows:

  1. test.yml — Runs on every push/PR: lint + test
  2. deploy.yml — Runs on push to main (after tests pass): deploy to production

Start simple, add complexity only when you need it.


More developer guides at lucasmdevdev.github.io

Top comments (0)