Skip to main content
Generated projects ship with GitHub Actions in .github/workflows/. They run on pull requests to main to verify Docker builds and enforce lint, type and format checks.

Build workflows

Build the API and Web Docker images to prove they compile.

Lint workflows

Run ESLint, TypeScript and Prettier via one reusable template.
The template provides five workflow files:
FilePurpose
build-api.ymlBuild the API Docker image
build-web.ymlBuild the Web Docker image
linter.template.ymlReusable lint job
run-api-linter.ymlLint the API
run-web-linter.ymlLint the Web app
Web-only projects have no apps/api, so the build-api.yml and run-api-linter.yml workflows aren’t included — only the web build and lint workflows ship.

Build workflows

Each build workflow builds the app’s Docker image with BuildKit layer caching, to catch a broken build before merge.

Build API — build-api.yml

Triggers on PRs to main touching apps/api/** or packages/**.
on:
  pull_request:
    branches:
      - main
    paths:
      - apps/api/**
      - packages/**

jobs:
  build:
    steps:
      - uses: docker/build-push-action@v5
        with:
          context: .
          file: ./apps/api/Dockerfile
          push: false
          cache-from: type=local,src=/tmp/.buildx-cache

Build Web — build-web.yml

Same shape, scoped to apps/web/** (and packages/**), building ./apps/web/Dockerfile.
on:
  pull_request:
    branches:
      - main
    paths:
      - apps/web/**
      - packages/**

Lint workflows

Linting runs through one reusable workflow that both the API and Web jobs call.

Reusable template — linter.template.yml

Pins the toolchain and runs ESLint, TypeScript and Prettier through lint-action, which posts inline comments on the PR.
env:
  PNPM_VERSION: 9.5.0
  NODE_VERSION: 22.13.0

# ...
      - name: Run Linters
        uses: wearerequired/lint-action@v2
        with:
          eslint: true
          eslint_dir: ${{ inputs.dir }}
          eslint_extensions: ts,tsx
          tsc: true
          tsc_dir: ${{ inputs.dir }}
          tsc_extensions: ts,tsx
          prettier: true
          prettier_dir: ${{ inputs.dir }}

Lint API & Web — run-api-linter.yml, run-web-linter.yml

Each one is a thin caller that passes a component and dir into the template:
jobs:
  lint:
    uses: ./.github/workflows/linter.template.yml
    with:
      component: api
      dir: apps/api
Both trigger on PRs to main that touch the matching app or packages/**.

Customization

Update Node.js / pnpm versions

Bump them once in linter.template.yml — both lint jobs inherit the change:
env:
  PNPM_VERSION: 9.5.0
  NODE_VERSION: 22.13.0
Every workflow also defines workflow_dispatch, so you can trigger any of them manually from the Actions tab.