GitHub Actions Architecture
GitHub Actions uses YAML workflow files in .github/workflows/ that define automated pipelines triggered by events (push, pull_request, schedule, manual). Each workflow contains jobs that run on virtual machines (runners). Each job contains steps that execute commands or reusable actions.
Key architecture concepts: Jobs run in parallel by default (add needs: for dependencies). Each job runs on a fresh VM (no shared state between jobs unless you use artifacts). Steps within a job share the same filesystem and environment.
GitHub provides hosted runners (Ubuntu, Windows, macOS) with 2-core CPUs and 7GB RAM. For faster builds, use larger runners or self-hosted runners.
Key Takeaways
Production CI Pipeline: Lint, Test, Build
A production CI pipeline runs on every push and pull request. It validates code quality, runs tests, builds the application, and reports results — all before code reaches the main branch.
The key optimization is dependency caching: without it, every CI run re-downloads all npm packages (30-60 seconds). With caching, subsequent runs restore packages from cache in 2-5 seconds.
# .github/workflows/ci.yml name: CI Pipeline on: push: branches: [main] pull_request: branches: [main] jobs: quality: name: Lint & Type Check runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 with: version: 9 - uses: actions/setup-node@v4 with: node-version: 22 cache: 'pnpm' # Caches pnpm store - run: pnpm install --frozen-lockfile - run: pnpm lint - run: pnpm check-types test: name: Tests runs-on: ubuntu-latest needs: quality # Only run if lint passes services: postgres: image: postgres:17 env: POSTGRES_DB: test_db POSTGRES_PASSWORD: test ports: ['5432:5432'] options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 with: { version: 9 } - uses: actions/setup-node@v4 with: { node-version: 22, cache: 'pnpm' } - run: pnpm install --frozen-lockfile - name: Run Tests run: pnpm test -- --coverage env: DATABASE_URL: postgresql://postgres:test@localhost:5432/test_db - name: Upload Coverage uses: actions/upload-artifact@v4 with: name: coverage-report path: coverage/ build: name: Build runs-on: ubuntu-latest needs: test steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 with: { version: 9 } - uses: actions/setup-node@v4 with: { node-version: 22, cache: 'pnpm' } - run: pnpm install --frozen-lockfile - run: pnpm build
Key Takeaways
Matrix Strategy: Test Across Versions
Matrix strategies run the same job across multiple configurations simultaneously — Node versions, OS versions, database versions, etc. This ensures your code works across all supported environments without writing duplicate jobs.
The matrix creates a cartesian product of all dimensions. A matrix with 3 Node versions and 2 OS versions creates 6 parallel jobs. Use exclude to skip specific combinations and include to add one-off configurations.
jobs:
test:
name: Test (Node ${{ matrix.node }}, ${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false # Don't cancel other jobs if one fails
matrix:
node: [20, 22]
os: [ubuntu-latest, windows-latest]
exclude:
- node: 20
os: windows-latest # Skip Node 20 on Windows
include:
- node: 23
os: ubuntu-latest
experimental: true # One-off: test Node 23 nightly
continue-on-error: ${{ matrix.experimental || false }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- run: npm ci
- run: npm testReusable Workflows: DRY CI/CD
Reusable workflows eliminate duplication across repositories. Define a workflow once, call it from any repository. This is how large organizations standardize CI/CD practices across 100+ repositories.
The reusable workflow is defined with workflow_call trigger and can accept inputs and secrets. The caller workflow uses the uses: keyword to reference it.
# .github/workflows/reusable-deploy.yml (in shared repo) name: Reusable Deploy on: workflow_call: inputs: environment: required: true type: string image-tag: required: true type: string secrets: DEPLOY_TOKEN: required: true jobs: deploy: runs-on: ubuntu-latest environment: ${{ inputs.environment }} steps: - name: Deploy to ${{ inputs.environment }} run: | echo "Deploying ${{ inputs.image-tag }} to ${{ inputs.environment }}" # kubectl set image deployment/app app=${{ inputs.image-tag }} # Caller workflow (in any repo) # .github/workflows/release.yml name: Release on: push: tags: ['v*'] jobs: build: runs-on: ubuntu-latest outputs: image-tag: ${{ steps.meta.outputs.tags }} steps: - uses: actions/checkout@v4 # ... build and push Docker image deploy-staging: needs: build uses: org/shared-workflows/.github/workflows/reusable-deploy.yml@main with: environment: staging image-tag: ${{ needs.build.outputs.image-tag }} secrets: DEPLOY_TOKEN: ${{ secrets.STAGING_TOKEN }} deploy-production: needs: deploy-staging uses: org/shared-workflows/.github/workflows/reusable-deploy.yml@main with: environment: production image-tag: ${{ needs.build.outputs.image-tag }} secrets: DEPLOY_TOKEN: ${{ secrets.PROD_TOKEN }}
Key Takeaways
OIDC: Keyless Cloud Authentication
OIDC (OpenID Connect) eliminates the need for long-lived cloud credentials (AWS keys, GCP service account keys) in your GitHub secrets. Instead, GitHub Actions requests a short-lived token from your cloud provider for each workflow run.
This is more secure because: no long-lived secrets to rotate or leak, tokens expire in minutes, and you can restrict which repositories and branches can assume which cloud roles.
OIDC is supported by AWS, Azure, GCP, HashiCorp Vault, and most cloud providers.
# OIDC with AWS — no AWS_ACCESS_KEY_ID needed! jobs: deploy: runs-on: ubuntu-latest permissions: id-token: write # Required for OIDC contents: read steps: - uses: actions/checkout@v4 - name: Configure AWS Credentials (OIDC) uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: arn:aws:iam::123456789:role/github-actions-deploy aws-region: ap-south-1 # No access key or secret needed! - name: Deploy to S3 run: aws s3 sync ./dist s3://inkandhorizon-prod --delete - name: Invalidate CloudFront run: aws cloudfront create-invalidation --distribution-id E1234 --paths "/*"
Key Takeaways
GitHub Actions CI/CD in 2026 is about: dependency caching (save 30-60s per run), matrix strategies (test across versions), reusable workflows (DRY across repos), OIDC (keyless cloud auth), and service containers (databases in CI).
For interviews: explain the workflow → job → step hierarchy, demonstrate caching patterns, discuss OIDC vs static credentials, and show how reusable workflows work across repositories.