<KodLexikon/>
Automatiserad CI/CD-pipeline med gröna checkmarks i terminalen
← Alla artiklar
devops12 min läsning2026-04-15

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 merge

GitHub 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 build

Det ä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:latest

Miljö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 sekunder

Branch 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örst

Pipeline 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 build

Databas 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 test

Monitoring: 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 services

Summering

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.