CI/CD pipeline med GitHub Actions: Från test till deploy
Automatisera lint, tester, build och deployment med GitHub Actions. Branch protection, hemligheter, caching och databas i CI. Komplett pipeline på en timme.
Bild: Growtika / Unsplash
Du pushar kod. Tester körs automatiskt. Bygget skapas. Det deployas till produktion. Ingen manuell SSH, inga glömda steg, ingen fredagsdeployment som går snett för att någon hoppade över testerna. Det är CI/CD.
Den här guiden visar hur du sätter upp en komplett CI/CD-pipeline med GitHub Actions — från första testet till automatisk deployment. Ingen överkonstruktion, bara det som faktiskt behövs.
CI vs CD: Två saker, ofta förväxlade
Continuous Integration (CI) betyder att varje push eller pull request automatiskt bygger koden och kör tester. Det fångar buggar innan de når main-branchen.
Continuous Delivery (CD) betyder att koden kan deployas till produktion automatiskt efter att CI passerat. Continuous Deployment går ett steg längre: varje merge till main deployas direkt, utan manuellt godkännande.
# Så här hänger det ihop:
#
# Push till branch
# └── CI: Lint + Test + Build
# └── Pull Request godkänd
# └── Merge till main
# └── CD: Deploy till produktion
#
# CI fångar fel FÖRE merge
# CD levererar EFTER mergeGitHub Actions: Din första pipeline
GitHub Actions är den mest använda CI/CD-plattformen för open source och team som redan använder GitHub. Konfigurationen är en YAML-fil i ditt repo.
# .github/workflows/ci.yml
name: CI
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: 22
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Lint
run: npm run lint
- name: Type check
run: npx tsc --noEmit
- name: Run tests
run: npm test
- name: Build
run: npm run buildDet är allt. Varje push och pull request kör nu lint, typkontroll, tester och bygge automatiskt. Om något steg felar blockeras mergen.
Steg 2: Parallella jobb och matris-testning
En pipeline som kör allt sekventiellt tar för lång tid. Dela upp i parallella jobb och testa mot flera Node-versioner.
# .github/workflows/ci.yml (utökad)
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: 'npm'
- run: npm ci
- run: npm run lint
- run: npx tsc --noEmit
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [20, 22]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm ci
- run: npm test
build:
needs: [lint, test] # Kör EFTER lint och test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: 'npm'
- run: npm ci
- run: npm run build
- uses: actions/upload-artifact@v4
with:
name: build-output
path: dist/Steg 3: Automatisk deployment
CI är klart. Nu vill du att koden deployas automatiskt när en merge till main passerar alla tester. Här finns flera vägar beroende på din hosting.
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
needs: [test, build] # Refererar till CI-pipeline
steps:
- uses: actions/checkout@v4
# Vercel (Next.js, React, etc.)
- 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'
# ALTERNATIV: Docker-baserad deploy
# - name: Build Docker image
# run: docker build -t app:latest .
# - name: Push to registry
# run: |
# docker tag app:latest ghcr.io/user/app:latest
# docker push ghcr.io/user/app:latestMiljövariabler och hemligheter
API-nycklar och tokens ska aldrig hårdkodas. GitHub Actions har inbyggd hantering av hemligheter med kryptering.
# Lägg till hemligheter i GitHub:
# Settings → Secrets and variables → Actions → New repository secret
# Använd i workflow:
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
API_KEY: ${{ secrets.API_KEY }}
# Environment-baserade hemligheter (staging vs production)
jobs:
deploy-staging:
environment: staging # Använder staging-hemligheter
steps:
- run: echo "Deploying to staging"
deploy-production:
environment: production # Kräver manuellt godkännande
needs: deploy-staging
steps:
- run: echo "Deploying to production"
# VARNING: Skriv ALDRIG ut hemligheter i loggar
# GitHub maskerar dem, men undvik:
# run: echo ${{ secrets.API_KEY }} # DÅLIGT!Caching: Snabbare pipelines
Att installera dependencies varje gång slösar tid. GitHub Actions cachar automatiskt med setup-node och cache-parametern, men du kan optimera ytterligare.
# Automatisk cache via setup-node (enklast)
- uses: actions/setup-node@v4
with:
node-version: 22
cache: 'npm' # Cachar ~/.npm baserat på package-lock.json
# Manuell cache (mer kontroll)
- uses: actions/cache@v4
with:
path: |
node_modules
~/.npm
key: deps-${{ hashFiles('package-lock.json') }}
restore-keys: |
deps-
# Resultat:
# Utan cache: npm ci tar ~45 sekunder
# Med cache: npm ci tar ~8 sekunderBranch Protection: Tvinga CI före merge
En pipeline som ingen behöver respektera är värdelös. Branch protection rules tvingar alla utvecklare att passera CI innan kod når main.
# GitHub: Settings → Branches → Branch protection rules
# Rekommenderade inställningar:
# ✅ Require a pull request before merging
# ✅ Require status checks to pass
# └── Välj: "lint", "test", "build"
# ✅ Require branches to be up to date
# ✅ Require conversation resolution
# ❌ Allow force pushes (ALDRIG på main!)
# Resultat:
# - Ingen kan pusha direkt till main
# - Alla ändringar kräver PR + godkänd CI
# - Merge-konflikter måste lösas förstPipeline för monorepos
Om du har frontend och backend i samma repo vill du inte köra alla tester för backend när du bara ändrar en CSS-fil. Filtrera på paths.
# .github/workflows/frontend.yml
name: Frontend CI
on:
pull_request:
paths:
- 'apps/web/**'
- 'packages/ui/**'
- 'package-lock.json'
jobs:
test:
runs-on: ubuntu-latest
defaults:
run:
working-directory: apps/web
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: 'npm'
- run: npm ci
- run: npm test
- run: npm run buildDatabas i CI: Tester med riktig data
Mocka inte databasen i CI. Kör en riktig PostgreSQL-instans som service och testa mot den.
jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:17
env:
POSTGRES_PASSWORD: testpass
POSTGRES_DB: testdb
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
DATABASE_URL: postgresql://postgres:testpass@localhost:5432/testdb
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: 'npm'
- run: npm ci
- name: Run migrations
run: npx prisma migrate deploy
- name: Run tests
run: npm testMonitoring: Vet du att din deploy fungerade?
En deploy utan monitoring är som att skicka ett brev utan returadress. Du vet inte om det kom fram.
# Lägg till i deploy-steget:
- name: Health check
run: |
sleep 10 # Vänta på att deplyen stabiliseras
STATUS=$(curl -s -o /dev/null -w '%{http_code}' https://min-app.se)
if [ "$STATUS" != "200" ]; then
echo "Health check failed! Status: $STATUS"
exit 1
fi
echo "Health check passed: $STATUS"
# Skicka notifikation vid deploy
- name: Notify on success
if: success()
run: |
curl -X POST "${{ secrets.SLACK_WEBHOOK }}" \
-H "Content-Type: application/json" \
-d '{"text": "Deployed to production: ${{ github.sha }}"}'
- name: Notify on failure
if: failure()
run: |
curl -X POST "${{ secrets.SLACK_WEBHOOK }}" \
-H "Content-Type: application/json" \
-d '{"text": "Deploy FAILED: ${{ github.sha }}"}'Checklista: Din CI/CD-pipeline
Bygg inte allt på en gång. Börja med grunderna och utöka när behovet uppstår.
# Steg 1: Grundläggande CI (dag 1)
# ✅ Lint (ESLint/Biome)
# ✅ Typkontroll (tsc --noEmit)
# ✅ Enhetstester
# ✅ Build
# Steg 2: Branch protection (dag 1)
# ✅ Kräv PR för merge till main
# ✅ Kräv godkänd CI
# Steg 3: Automatisk deploy (vecka 1)
# ✅ Deploy vid merge till main
# ✅ Health check efter deploy
# ✅ Notifikation vid fel
# Steg 4: Utöka vid behov
# ⬜ Matris-testning (flera Node-versioner)
# ⬜ E2E-tester (Playwright/Cypress)
# ⬜ Staging-miljö med manuellt godkännande
# ⬜ Caching-optimering
# ⬜ Databas-tester med servicesSummering
CI/CD handlar inte om verktyg. Det handlar om att automatisera de steg som annars glöms bort. Lint, tester, build och deploy ska ske automatiskt vid varje push. GitHub Actions gör det med en YAML-fil i ditt repo.
Börja med en enkel pipeline: lint + test + build. Lägg till branch protection så att ingen kan kringgå den. Automatisera deploy när du har förtroende för dina tester. Det tar en timme att sätta upp och sparar hundratals timmar av "det fungerade på min maskin".
Använder du Docker i din pipeline? Läs vår Docker-guide för multi-stage builds och container-optimering. Behöver du en branching-strategi som fungerar med CI/CD? Vi har jämfört trunk-based, Git Flow och GitHub Flow. Och om din pipeline kör databas-migrations, kolla PostgreSQL-guiden för Prisma och Drizzle setup.