Przejdź do treści
DevOps

CI/CD mit GitHub Actions fuer Next.js und .NET - Komplettanleitung

Veröffentlicht am:
·4 Min. Lesezeit·Autor: MDS Software Solutions Group

CI/CD mit GitHub

devops

CI/CD mit GitHub Actions fuer Next.js und .NET

Die Automatisierung des Prozesses zum Erstellen, Testen und Bereitstellen von Anwendungen ist das Fundament der modernen Softwareentwicklung. GitHub Actions, direkt in die GitHub-Plattform integriert, ermoeglicht die Erstellung anspruchsvoller CI/CD-Pipelines ohne die Konfiguration externer Tools. In diesem Leitfaden zeigen wir Ihnen, wie Sie komplette Workflows fuer Next.js- und .NET-Projekte einrichten — vom ersten Commit bis zum Produktions-Deployment.

Was ist CI/CD?#

Continuous Integration (CI) ist die Praxis, Code-Aenderungen haeufig in den Hauptbranch eines Repositories zusammenzufuehren. Jede Aenderung wird automatisch durch automatisierte Tests und Build-Prozesse verifiziert, was eine fruehzeitige Erkennung von Fehlern und Integrationsproblemen ermoeglicht.

Continuous Delivery / Continuous Deployment (CD) erweitert CI um automatisierte Anwendungsbereitstellung. Continuous Delivery bedeutet, dass jede Aenderung, die die Tests besteht, bereit fuer das Deployment ist (aber eine manuelle Genehmigung erfordert). Continuous Deployment geht einen Schritt weiter — es stellt automatisch jede Aenderung bereit, die die Pipeline durchlaeuft.

Vorteile der CI/CD-Implementierung:

  • Schnellere Fehlererkennung — Probleme werden sofort nach jedem Commit identifiziert
  • Kuerzere Lieferzeiten — vom Commit zur Produktion in Minuten
  • Hoehere Codequalitaet — automatisierte Tests und Linting bei jeder Aenderung
  • Reproduzierbarkeit — jedes Deployment folgt dem exakt gleichen Prozess
  • Geringeres Risiko — kleine, haeufige Aenderungen statt grosser, riskanter Deployments

GitHub Actions — Plattformuebersicht#

GitHub Actions ist eine CI/CD-Plattform, die direkt in GitHub integriert ist. Sie bietet:

  • Kostenlose Minuten fuer oeffentliche Repositories (unbegrenzt) und private Repositories (2.000 Min./Monat im Free-Plan)
  • Hosted Runners — virtuelle Maschinen mit Linux, Windows und macOS
  • Self-hosted Runners — die Moeglichkeit, Workflows auf der eigenen Infrastruktur auszufuehren
  • Marketplace — Tausende vorgefertigter Actions der Community
  • GitHub-Integration — native Unterstuetzung fuer Pull Requests, Issues und Deployments

Workflow-Syntax — Anatomie einer YAML-Datei#

Jeder GitHub Actions Workflow ist eine YAML-Datei im Verzeichnis .github/workflows/. Hier sind die wichtigsten Elemente der Syntax:

# .github/workflows/ci.yml
name: CI Pipeline                    # Workflow-Name

on:                                   # Trigger (Ausloeser)
  push:
    branches: [main, develop]        # Ausfuehren bei Push nach main/develop
  pull_request:
    branches: [main]                 # Ausfuehren bei PR nach main
  workflow_dispatch:                 # Manuelle Ausfuehrung erlauben

env:                                  # Umgebungsvariablen (global)
  NODE_VERSION: "20"
  DOTNET_VERSION: "8.0.x"

jobs:                                 # Job-Definitionen
  build:                             # Job-Name
    runs-on: ubuntu-latest           # Runner
    timeout-minutes: 15              # Timeout

    steps:                           # Job-Schritte
      - name: Checkout code
        uses: actions/checkout@v4    # Vorgefertigte Action verwenden

      - name: Run custom script
        run: echo "Hello CI/CD!"     # Shell-Befehl ausfuehren

Trigger (Ausloeser)#

GitHub Actions unterstuetzt viele Arten von Triggern:

on:
  push:
    branches: [main, develop]
    paths:
      - "src/**"                     # Nur wenn sich Dateien in src/ aendern
      - "!docs/**"                   # Aenderungen in docs/ ignorieren
    tags:
      - "v*"                         # Ausfuehren bei Tags wie v1.0, v2.1 usw.

  pull_request:
    types: [opened, synchronize, reopened]
    branches: [main]

  schedule:
    - cron: "0 6 * * 1"             # Jeden Montag um 6:00 Uhr UTC

  workflow_dispatch:                 # Manuelle Ausfuehrung
    inputs:
      environment:
        description: "Target environment"
        required: true
        default: "staging"
        type: choice
        options:
          - staging
          - production

Jobs und Steps#

Jobs laufen standardmaessig parallel. Sie koennen Abhaengigkeiten zwischen ihnen definieren:

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

  test:
    runs-on: ubuntu-latest
    needs: lint                      # Nach Abschluss von lint ausfuehren
    steps:
      - uses: actions/checkout@v4
      - run: npm test

  deploy:
    runs-on: ubuntu-latest
    needs: [lint, test]              # Nach lint UND test ausfuehren
    if: github.ref == 'refs/heads/main'  # Nur auf dem main-Branch
    steps:
      - run: echo "Deploying..."

Next.js CI/CD Workflow#

Der folgende Workflow umfasst eine komplette Pipeline fuer eine Next.js-Anwendung — vom Linting bis zum Vercel-Deployment:

# .github/workflows/nextjs-ci-cd.yml
name: Next.js CI/CD

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

env:
  NODE_VERSION: "20"

jobs:
  # ─── Phase 1: Lint ──────────────────────────
  lint:
    name: Lint & Format Check
    runs-on: ubuntu-latest
    timeout-minutes: 10

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: "npm"

      - name: Install dependencies
        run: npm ci

      - name: Run ESLint
        run: npm run lint

      - name: Check Prettier formatting
        run: npx prettier --check "src/**/*.{ts,tsx,js,jsx}"

      - name: TypeScript type check
        run: npx tsc --noEmit

  # ─── Phase 2: Tests ─────────────────────────
  test:
    name: Unit & Integration Tests
    runs-on: ubuntu-latest
    needs: lint
    timeout-minutes: 15

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: "npm"

      - name: Install dependencies
        run: npm ci

      - name: Run tests with coverage
        run: npm run test -- --coverage --ci
        env:
          CI: true

      - name: Upload coverage report
        uses: actions/upload-artifact@v4
        with:
          name: coverage-report
          path: coverage/
          retention-days: 7

  # ─── Phase 3: Build ─────────────────────────
  build:
    name: Build Application
    runs-on: ubuntu-latest
    needs: test
    timeout-minutes: 15

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: "npm"

      - name: Install dependencies
        run: npm ci

      - name: Build Next.js application
        run: npm run build
        env:
          NEXT_PUBLIC_API_URL: ${{ secrets.NEXT_PUBLIC_API_URL }}
          NEXT_PUBLIC_SITE_URL: ${{ secrets.NEXT_PUBLIC_SITE_URL }}

      - name: Upload build artifacts
        uses: actions/upload-artifact@v4
        with:
          name: nextjs-build
          path: .next/
          retention-days: 1

  # ─── Phase 4: Deploy auf Vercel ─────────────
  deploy-staging:
    name: Deploy to Staging
    runs-on: ubuntu-latest
    needs: build
    if: github.ref == 'refs/heads/develop'
    environment:
      name: staging
      url: ${{ steps.deploy.outputs.url }}

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Deploy to Vercel (Preview)
        id: 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 }}
          scope: ${{ secrets.VERCEL_ORG_ID }}

  deploy-production:
    name: Deploy to Production
    runs-on: ubuntu-latest
    needs: build
    if: github.ref == 'refs/heads/main'
    environment:
      name: production
      url: ${{ steps.deploy.outputs.url }}

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Deploy to Vercel (Production)
        id: 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: "--prod"
          scope: ${{ secrets.VERCEL_ORG_ID }}

.NET CI/CD Workflow#

Hier ist eine komplette Pipeline fuer eine .NET-Anwendung, die Build, Tests und Veroeffentlichung umfasst:

# .github/workflows/dotnet-ci-cd.yml
name: .NET CI/CD

on:
  push:
    branches: [main, develop]
    paths:
      - "src/**"
      - "tests/**"
      - "*.sln"
      - "*.csproj"
  pull_request:
    branches: [main]

env:
  DOTNET_VERSION: "8.0.x"
  DOTNET_NOLOGO: true
  DOTNET_CLI_TELEMETRY_OPTOUT: true
  SOLUTION_PATH: "./MyApp.sln"

jobs:
  # ─── Phase 1: Build & Test ──────────────────
  build-and-test:
    name: Build & Test
    runs-on: ubuntu-latest
    timeout-minutes: 15

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup .NET SDK
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: ${{ env.DOTNET_VERSION }}

      - name: Restore NuGet packages
        run: dotnet restore ${{ env.SOLUTION_PATH }}

      - name: Build solution
        run: dotnet build ${{ env.SOLUTION_PATH }} --configuration Release --no-restore

      - name: Run unit tests
        run: |
          dotnet test ${{ env.SOLUTION_PATH }} \
            --configuration Release \
            --no-build \
            --verbosity normal \
            --collect:"XPlat Code Coverage" \
            --results-directory ./test-results

      - name: Upload test results
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: test-results
          path: ./test-results/
          retention-days: 7

  # ─── Phase 2: Code-Analyse ──────────────────
  code-analysis:
    name: Code Analysis
    runs-on: ubuntu-latest
    needs: build-and-test
    timeout-minutes: 10

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup .NET SDK
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: ${{ env.DOTNET_VERSION }}

      - name: Run dotnet format check
        run: dotnet format ${{ env.SOLUTION_PATH }} --verify-no-changes --verbosity diagnostic

  # ─── Phase 3: Publish ───────────────────────
  publish:
    name: Publish Application
    runs-on: ubuntu-latest
    needs: [build-and-test, code-analysis]
    if: github.ref == 'refs/heads/main'
    timeout-minutes: 10

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup .NET SDK
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: ${{ env.DOTNET_VERSION }}

      - name: Publish application
        run: |
          dotnet publish src/MyApp.Api/MyApp.Api.csproj \
            --configuration Release \
            --output ./publish \
            --self-contained false \
            --runtime linux-x64

      - name: Upload published artifacts
        uses: actions/upload-artifact@v4
        with:
          name: dotnet-publish
          path: ./publish/
          retention-days: 5

Docker Build and Push#

Das Erstellen und Veroeffentlichen von Docker-Images ist ein wesentlicher Bestandteil jeder CD-Pipeline. Hier ist ein Workflow, der ein Image erstellt und in die GitHub Container Registry (GHCR) pusht:

# .github/workflows/docker-build.yml
name: Docker Build & Push

on:
  push:
    branches: [main]
    tags: ["v*.*.*"]
  pull_request:
    branches: [main]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  docker:
    name: Build & Push Docker Image
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

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

      - name: Login to GitHub Container Registry
        if: github.event_name != 'pull_request'
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata (tags, labels)
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=ref,event=branch
            type=ref,event=pr
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}
            type=sha,prefix=

      - name: Build and push Docker image
        uses: docker/build-push-action@v5
        with:
          context: .
          push: ${{ github.event_name != 'pull_request' }}
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max
          build-args: |
            BUILD_VERSION=${{ github.sha }}

Abhaengigkeiten cachen#

Richtiges Caching kann die Pipeline-Ausfuehrungszeit um bis zu 70% reduzieren. Hier sind Strategien fuer verschiedene Technologien:

Node.js / Next.js Cache#

- name: Setup Node.js with cache
  uses: actions/setup-node@v4
  with:
    node-version: "20"
    cache: "npm"                    # Automatischer node_modules Cache

# Oder manuelles Caching fuer mehr Kontrolle:
- name: Cache Node modules
  uses: actions/cache@v4
  id: npm-cache
  with:
    path: |
      ~/.npm
      .next/cache
    key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/*.ts', '**/*.tsx') }}
    restore-keys: |
      ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-
      ${{ runner.os }}-nextjs-

.NET Cache#

- name: Cache NuGet packages
  uses: actions/cache@v4
  with:
    path: ~/.nuget/packages
    key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }}
    restore-keys: |
      ${{ runner.os }}-nuget-

Docker Cache#

- name: Build with GitHub Actions cache
  uses: docker/build-push-action@v5
  with:
    context: .
    cache-from: type=gha
    cache-to: type=gha,mode=max

Umgebungsvariablen und Secrets#

GitHub Actions bietet mehrere Ebenen fuer die Verwaltung von Variablen und Secrets:

Konfigurationsebenen#

# Workflow-Ebene (in allen Jobs verfuegbar)
env:
  APP_NAME: "my-application"

jobs:
  deploy:
    # Job-Ebene
    env:
      DEPLOY_ENV: "staging"

    steps:
      - name: Build
        # Step-Ebene
        env:
          API_KEY: ${{ secrets.API_KEY }}
        run: echo "Building for $APP_NAME in $DEPLOY_ENV"

Environments (Umgebungen)#

GitHub Environments ermoeglichen es, Secrets und Schutzregeln pro Umgebung zu definieren:

jobs:
  deploy-staging:
    runs-on: ubuntu-latest
    environment:
      name: staging
      url: https://staging.example.com
    steps:
      - name: Deploy
        env:
          DATABASE_URL: ${{ secrets.DATABASE_URL }}     # Secret aus der Staging-Umgebung
          API_KEY: ${{ secrets.API_KEY }}
        run: ./deploy.sh

  deploy-production:
    runs-on: ubuntu-latest
    environment:
      name: production
      url: https://example.com
    needs: deploy-staging
    steps:
      - name: Deploy
        env:
          DATABASE_URL: ${{ secrets.DATABASE_URL }}     # Secret aus der Produktionsumgebung
        run: ./deploy.sh

Deployment-Strategien — Staging und Produktion#

Eine gut konzipierte Pipeline sollte mehrere Umgebungen mit entsprechenden Sicherheits-Gates unterstuetzen:

# .github/workflows/deploy.yml
name: Deploy Pipeline

on:
  push:
    branches: [main, develop]

jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci && npm run build

  deploy-staging:
    name: Deploy to Staging
    needs: build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/develop'
    environment:
      name: staging
      url: https://staging.myapp.com
    steps:
      - uses: actions/checkout@v4
      - name: Deploy to staging server
        run: |
          echo "Deploying to staging..."
          # Staging-Deployment-Befehl
        env:
          DEPLOY_TOKEN: ${{ secrets.STAGING_DEPLOY_TOKEN }}

  deploy-production:
    name: Deploy to Production
    needs: build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    environment:
      name: production                # Erfordert manuelle Genehmigung (in Repo-Settings konfiguriert)
      url: https://myapp.com
    steps:
      - uses: actions/checkout@v4
      - name: Deploy to production
        run: |
          echo "Deploying to production..."
          # Produktions-Deployment-Befehl
        env:
          DEPLOY_TOKEN: ${{ secrets.PROD_DEPLOY_TOKEN }}

      - name: Notify on success
        if: success()
        run: |
          curl -X POST "${{ secrets.SLACK_WEBHOOK }}" \
            -H "Content-Type: application/json" \
            -d '{"text":"Deployment to production successful! Commit: ${{ github.sha }}"}'

Branch Protection Rules und Status Checks#

Der Branch-Schutz ist ein kritisches Element der Pipeline-Sicherheit. Konfigurieren Sie ihn in den Repository-Einstellungen (Settings > Branches):

Empfohlene Regeln fuer den main-Branch:

  • Require pull request reviews — mindestens 1-2 Reviewer verlangen
  • Require status checks to pass — den CI-Workflow als erforderlich markieren
  • Require branches to be up to date — Rebase/Merge mit main vor dem Mergen erzwingen
  • Require signed commits — optional, fuer zusaetzliche Sicherheit
  • Do not allow bypassing — auch Admins muessen die Regeln befolgen

Status Checks integrieren sich direkt in Pull Requests:

# Dieser Job erscheint als erforderlicher Status Check
jobs:
  ci:
    name: "CI / Build & Test"        # Dieser Name erscheint in PRs
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm run lint
      - run: npm test
      - run: npm run build

Reusable Workflows — Wiederverwendbare Workflows#

Anstatt Konfigurationen zwischen Repositories zu kopieren, erstellen Sie wiederverwendbare Workflows:

# .github/workflows/reusable-nextjs-ci.yml
name: Reusable Next.js CI

on:
  workflow_call:                     # Aufruf aus anderen Workflows erlauben
    inputs:
      node-version:
        description: "Node.js version"
        required: false
        default: "20"
        type: string
      run-e2e:
        description: "Run E2E tests"
        required: false
        default: false
        type: boolean
    secrets:
      VERCEL_TOKEN:
        required: false
      SONAR_TOKEN:
        required: false

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

      - uses: actions/setup-node@v4
        with:
          node-version: ${{ inputs.node-version }}
          cache: "npm"

      - run: npm ci
      - run: npm run lint
      - run: npm test -- --ci

      - name: E2E Tests
        if: inputs.run-e2e
        run: npx playwright test

Aufruf eines wiederverwendbaren Workflows:

# .github/workflows/ci.yml
name: CI
on:
  pull_request:
    branches: [main]

jobs:
  nextjs-ci:
    uses: ./.github/workflows/reusable-nextjs-ci.yml
    with:
      node-version: "20"
      run-e2e: true
    secrets:
      VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}

Matrix Builds — Testen ueber mehrere Konfigurationen#

Die Matrix-Strategie ermoeglicht es, denselben Job auf mehreren Konfigurationen gleichzeitig auszufuehren:

jobs:
  test:
    name: Test on Node ${{ matrix.node-version }} / ${{ matrix.os }}
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false               # Andere Jobs bei Fehler nicht abbrechen
      matrix:
        node-version: [18, 20, 22]
        os: [ubuntu-latest, windows-latest]
        exclude:
          - os: windows-latest
            node-version: 18         # Diese Kombination ueberspringen

    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
      - run: npm ci
      - run: npm test

  test-dotnet:
    name: .NET Test on ${{ matrix.dotnet-version }}
    runs-on: ubuntu-latest
    strategy:
      matrix:
        dotnet-version: ["7.0.x", "8.0.x"]

    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-dotnet@v4
        with:
          dotnet-version: ${{ matrix.dotnet-version }}
      - run: dotnet test --configuration Release

Komplette Pipeline — Next.js + .NET in einem Repository#

Wenn Ihr Projekt eine Fullstack-Anwendung mit Next.js (Frontend) und .NET (Backend-API) ist, hier ein kombinierter Workflow:

# .github/workflows/fullstack-ci-cd.yml
name: Fullstack CI/CD

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

jobs:
  # ─── Frontend (Next.js) ─────────────────────
  frontend-ci:
    name: Frontend CI
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: ./frontend

    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: "20"
          cache: "npm"
          cache-dependency-path: frontend/package-lock.json

      - run: npm ci
      - run: npm run lint
      - run: npm test -- --ci
      - run: npm run build

  # ─── Backend (.NET) ─────────────────────────
  backend-ci:
    name: Backend CI
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: ./backend

    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-dotnet@v4
        with:
          dotnet-version: "8.0.x"

      - run: dotnet restore
      - run: dotnet build --configuration Release --no-restore
      - run: dotnet test --configuration Release --no-build

  # ─── Docker Build ───────────────────────────
  docker-build:
    name: Docker Build
    needs: [frontend-ci, backend-ci]
    runs-on: ubuntu-latest
    if: github.event_name == 'push'
    strategy:
      matrix:
        include:
          - context: ./frontend
            image: frontend
            dockerfile: ./frontend/Dockerfile
          - context: ./backend
            image: backend
            dockerfile: ./backend/Dockerfile

    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: ${{ matrix.context }}
          file: ${{ matrix.dockerfile }}
          push: true
          tags: ghcr.io/${{ github.repository }}/${{ matrix.image }}:${{ github.sha }}
          cache-from: type=gha,scope=${{ matrix.image }}
          cache-to: type=gha,scope=${{ matrix.image }},mode=max

  # ─── Deploy ─────────────────────────────────
  deploy:
    name: Deploy
    needs: docker-build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    environment: production

    steps:
      - name: Deploy to production
        run: |
          echo "Deploying frontend and backend..."
          # kubectl set image deployment/frontend ...
          # kubectl set image deployment/backend ...

Best Practices#

  1. Action-Versionen fixieren — verwenden Sie actions/checkout@v4 statt actions/checkout@main
  2. Berechtigungen einschraenken — setzen Sie permissions auf das minimal erforderliche Niveau
  3. Abhaengigkeiten cachen — nutzen Sie actions/cache oder eingebautes Caching in setup-node/setup-dotnet
  4. Timeouts setzentimeout-minutes verhindert haengengebliebene Jobs
  5. Pfade filtern — loesen Sie Workflows nur aus, wenn sich relevante Dateien aendern
  6. Environments verwenden — getrennte Secrets fuer Staging und Produktion
  7. Ausfuehrungszeit ueberwachen — optimieren Sie Pipelines, die 10 Minuten ueberschreiten
  8. Workflows versionieren — behandeln Sie YAML-Dateien wie Produktionscode

Zusammenfassung#

GitHub Actions ist eine leistungsstarke CI/CD-Plattform, die in Kombination mit Next.js und .NET eine komplette, automatisierte Pipeline vom Commit bis zum Produktions-Deployment ermoeglicht. Die Schluesselelemente sind richtiges Caching, Deployment-Strategien mit Umgebungstrennung, Branch-Schutz und wiederverwendbare Workflows.

Die Implementierung einer gut konzipierten CI/CD-Pipeline ist eine Investition, die sich vielfach auszahlt — durch schnellere Deployments, hoehere Codequalitaet und ruhigeren Schlaf fuer das Entwicklungsteam.


Brauchen Sie eine professionelle CI/CD-Konfiguration fuer Ihr Projekt? Bei MDS Software Solutions Group entwerfen und implementieren wir fortschrittliche CI/CD-Pipelines fuer Next.js, .NET und darueber hinaus. Von einfachen Konfigurationen bis hin zu komplexen, Multi-Umgebungs-Deployments mit Docker und Kubernetes — wir helfen Ihnen, Ihren gesamten Software-Delivery-Prozess zu automatisieren. Kontaktieren Sie uns, um Ihre DevOps-Anforderungen zu besprechen.

Autor
MDS Software Solutions Group

Team von Programmierexperten, die sich auf moderne Webtechnologien spezialisiert haben.

CI/CD mit GitHub Actions fuer Next.js und .NET - Komplettanleitung | MDS Software Solutions Group | MDS Software Solutions Group