Tilbake til bloggen
Guide1. mars 2026

GitHub Actions: CI/CD-pipelines som faktisk fungerer

Jeg husker de første prosjektene mine der deploy betød å SSH-e inn på en server, kjøre git pull og be en stille bønn. Så kom Jenkins — som løste automatiseringsproblemene, men skapte nye med sin Java-baserte infrastruktur og XML-konfigurasjon. Da GitHub Actions kom, var det en lettelse: CI/CD som bor der koden allerede er.

Nå bruker jeg GitHub Actions i nesten alle prosjektene mine — fra denne nettsiden til Tuli sin backend. Dette innlegget handler om hvordan jeg strukturerer workflows i praksis, med konkrete eksempler du kan bruke direkte.

Hvorfor GitHub Actions?

Integrasjon med GitHub. Workflows trigges av push, pull requests, releases, issues — alt som skjer i repoet. Ingen webhook-oppsett, ingen ekstern CI-server å vedlikeholde.

Gratis for open source. Offentlige repoer får ubegrensede minutter. For private repoer er gratiskvoten sjenerøs nok til de fleste sideprosjekter.

Marketplace med tusenvis av actions. Trenger du å deploye til Firebase? Kjøre Lighthouse? Publisere til npm? Sjansen er stor for at noen allerede har laget en action for det.

YAML-basert konfigurasjon. Alt er versjonskontrollert i .github/workflows/. Ingen hemmeligheter gjemt i CI-serveren — workflow-definisjonen lever sammen med koden.

CI-workflow for Next.js

La oss starte med det mest grunnleggende: en CI-pipeline som kjører på hver pull request. Denne sjekker at koden kompilerer, at linting passerer, og at testene er grønne.

name: CI

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

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

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

      - run: npm ci

      - run: npm run lint
      - run: npm run type-check
      - run: npm run build
      - run: npm test -- --passWithNoTests

Noen viktige detaljer. npm ci istedenfor npm install er bevisst — den installerer nøyaktig det som står i package-lock.json, uten å oppdatere noe. cache: 'npm' i setup-node cacher ~/.npm-mappen mellom kjøringer, som sparer 30-60 sekunder per workflow. Rekkefølgen er viktig: lint først (raskest å feile), deretter type-check, så build, og til slutt tester.

Denne enkle workflowen fanger de fleste problemene. Noen glemmer å kjøre npm run build lokalt og pusher TypeScript-feil. Andre glemmer lint-fikser. CI er sikkerhetsnettet som fanger det teamet ikke gjør manuelt.

Caching-strategier

Caching er forskjellen mellom en pipeline som tar 5 minutter og en som tar 1 minutt. For Node.js-prosjekter er den innebygde cachen i setup-node et godt utgangspunkt, men for mer komplekse oppsett bruker jeg actions/cache direkte.

For Next.js-prosjekter cacher jeg .next/cache-mappen, som inneholder byggeresultater som kan gjenbrukes mellom kjøringer. For Docker-builds bruker jeg BuildKit-cache med type=gha som lagrer Docker-layers direkte i GitHub Actions sin cache.

Tommelregelen min: cache alt som er dyrt å generere og sjelden endres. node_modules (via npm ci + cache), Docker-layers, Go-moduler, byggeresultater.

Docker build og push

For backend-tjenester som Tuli sin API trenger jeg mer enn bare lint og test — jeg trenger å bygge et Docker-image og pushe det til et registry. Her er workflowen jeg bruker:

name: Build and Push

on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

    steps:
      - uses: actions/checkout@v4

      - uses: docker/setup-buildx-action@v3

      - uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: |
            ghcr.io/${{ github.repository }}:latest
            ghcr.io/${{ github.repository }}:${{ github.sha }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

Denne workflowen bruker GitHub Container Registry (ghcr.io), som er inkludert i GitHub-abonnementet. GITHUB_TOKEN er automatisk tilgjengelig — ingen manuelle secrets å sette opp. docker/setup-buildx-action aktiverer BuildKit, som gir bedre caching og muligheten til å bruke cache-from/cache-to med type=gha. Vi tagger med både latest og commit-SHA-en, slik at vi alltid kan rulle tilbake til en spesifikk versjon.

Ting jeg har lært den harde veien

Hold workflows enkle. Det er fristende å bygge et komplekst system med reusable workflows, matrix builds og conditional jobs. Start enkelt — splitt opp bare når du faktisk har duplisering.

Pin action-versjoner. uses: actions/checkout@v4 er greit for de mest brukte actions. For tredjepartsactions, pin til en spesifikk SHA for å unngå supply chain-angrep: uses: some-action@a1b2c3d4.

Bruk `concurrency` for å unngå redundante kjøringer. Når du pusher flere commits raskt etter hverandre, vil du ikke ha fem parallelle CI-kjøringer. concurrency: { group: ${{ github.ref }}, cancel-in-progress: true } kansellerer eldre kjøringer automatisk.

Secrets hører hjemme i repository settings. Aldri hardkod API-nøkler eller passord i workflow-filer. GitHub krypterer secrets og maskerer dem automatisk i logger.

Oppsummering

GitHub Actions har blitt min standard for CI/CD fordi det fjerner friksjon. Koden og pipelinen lever på samme sted, caching fungerer ut av boksen, og marketplace-økosystemet dekker de fleste behov. Start med en enkel CI-workflow for pull requests, legg til Docker-bygg når du trenger det, og bygg videre derfra.

#github-actions#ci-cd#devops#automatisering

Nyhetsbrev

Få nye innlegg rett i innboksen.