> ## Documentation Index
> Fetch the complete documentation index at: https://ship.paralect.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# GitHub Actions

> Pre-wired CI — Docker build checks and a reusable lint workflow on every pull request.

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.

<CardGroup cols={2}>
  <Card title="Build workflows" icon="docker">
    Build the API and Web Docker images to prove they compile.
  </Card>

  <Card title="Lint workflows" icon="broom">
    Run ESLint, TypeScript and Prettier via one reusable template.
  </Card>
</CardGroup>

The template provides five workflow files:

| File                  | Purpose                    |
| --------------------- | -------------------------- |
| `build-api.yml`       | Build the API Docker image |
| `build-web.yml`       | Build the Web Docker image |
| `linter.template.yml` | Reusable lint job          |
| `run-api-linter.yml`  | Lint the API               |
| `run-web-linter.yml`  | Lint the Web app           |

<Note>
  **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.
</Note>

## 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/**`.

```yaml theme={null}
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`.

```yaml theme={null}
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](https://github.com/wearerequired/lint-action), which posts inline comments on the PR.

```yaml theme={null}
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:

<CodeGroup>
  ```yaml run-api-linter.yml theme={null}
  jobs:
    lint:
      uses: ./.github/workflows/linter.template.yml
      with:
        component: api
        dir: apps/api
  ```

  ```yaml run-web-linter.yml theme={null}
  jobs:
    lint:
      uses: ./.github/workflows/linter.template.yml
      with:
        component: web
        dir: apps/web
  ```
</CodeGroup>

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:

```yaml theme={null}
env:
  PNPM_VERSION: 9.5.0
  NODE_VERSION: 22.13.0
```

<Tip>
  Every workflow also defines `workflow_dispatch`, so you can trigger any of them manually from the Actions tab.
</Tip>
