Skip to main content

GitHub Actions

AutoDeployBase generates CI/CD workflows for GitHub Actions.

Generated Workflows

CI Workflow

.github/workflows/ci.yml
name: CI

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

jobs:
lint:
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: Lint
run: npm run lint

typecheck:
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: Generate Prisma Client
run: npx prisma generate

- name: Type check
run: npm run typecheck

test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: test
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5

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: Generate Prisma Client
run: npx prisma generate

- name: Run migrations
run: npx prisma migrate deploy
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test

- name: Run tests
run: npm test
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test
JWT_SECRET: test-secret

build:
runs-on: ubuntu-latest
needs: [lint, typecheck, test]
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: Generate Prisma Client
run: npx prisma generate

- name: Build
run: npm run build

Deploy Workflow

.github/workflows/deploy.yml
name: Deploy

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'

Customization

Environment-Specific Deploys

.github/workflows/deploy.yml
name: Deploy

on:
push:
branches:
- main
- staging

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set environment
run: |
if [ "${{ github.ref }}" = "refs/heads/main" ]; then
echo "DEPLOY_ENV=production" >> $GITHUB_ENV
echo "VERCEL_ARGS=--prod" >> $GITHUB_ENV
else
echo "DEPLOY_ENV=staging" >> $GITHUB_ENV
echo "VERCEL_ARGS=" >> $GITHUB_ENV
fi

- name: Deploy
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: ${{ env.VERCEL_ARGS }}

Docker Build and Push

.github/workflows/docker.yml
name: Docker

on:
push:
branches: [main]
tags: ['v*']

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: username/my-app
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=sha

- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
cache-from: type=gha
cache-to: type=gha,mode=max

Database Migrations

.github/workflows/migrate.yml
name: Database Migration

on:
workflow_dispatch:
push:
branches: [main]
paths:
- 'prisma/**'

jobs:
migrate:
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 migrations
run: npx prisma migrate deploy
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}

Secrets Management

Required Secrets

SecretDescription
VERCEL_TOKENVercel API token
VERCEL_ORG_IDVercel organization ID
VERCEL_PROJECT_IDVercel project ID
DATABASE_URLProduction database URL
DOCKERHUB_USERNAMEDocker Hub username
DOCKERHUB_TOKENDocker Hub access token

Setting Secrets

  1. Go to Repository → Settings → Secrets and variables → Actions
  2. Click "New repository secret"
  3. Add name and value

Using Secrets

env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
JWT_SECRET: ${{ secrets.JWT_SECRET }}

Caching

npm Cache

- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

Custom Cache

- name: Cache Prisma
uses: actions/cache@v4
with:
path: node_modules/.prisma
key: prisma-${{ hashFiles('prisma/schema.prisma') }}

Docker Layer Cache

- uses: docker/build-push-action@v5
with:
cache-from: type=gha
cache-to: type=gha,mode=max

Matrix Testing

Multiple Node Versions

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20, 22]
steps:
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}

Multiple Databases

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
database: [postgresql, sqlite]
services:
postgres:
image: ${{ matrix.database == 'postgresql' && 'postgres:16' || '' }}

Scheduled Jobs

Nightly Tests

name: Nightly Tests

on:
schedule:
- cron: '0 0 * * *' # Midnight UTC

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

Weekly Dependency Updates

name: Update Dependencies

on:
schedule:
- cron: '0 0 * * 0' # Sunday midnight

jobs:
update:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Update dependencies
run: |
npm update
npm audit fix

- name: Create PR
uses: peter-evans/create-pull-request@v6
with:
title: 'chore: update dependencies'
branch: deps/weekly-update

Notifications

Slack

- name: Notify Slack
uses: slackapi/slack-github-action@v1
with:
channel-id: 'deployments'
slack-message: 'Deployed ${{ github.sha }} to production'
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}

Discord

- name: Notify Discord
uses: sarisia/actions-status-discord@v1
with:
webhook: ${{ secrets.DISCORD_WEBHOOK }}
status: ${{ job.status }}