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 -- --passWithNoTestsNoen 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=maxDenne 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.