# What CI/CD Pipelines Are Defined in .github/workflows for open-seo?

> Discover the four CI/CD pipelines in .github/workflows for open-seo: core checks, Docker builds, error tracking, and preview deployments. Understand your GitHub Actions.

- Repository: [Every App/open-seo](https://github.com/every-app/open-seo)
- Tags: how-to-guide
- Published: 2026-08-16

---

**The open-seo repository defines four GitHub Actions workflows in `.github/workflows`: ci.yml for core checks, docker-image.yml for multi-arch container builds, sourcemaps.yml for PostHog error tracking, and pr-preview.yml for Cloudflare Workers preview deployments.**

The **open-seo** project by every-app automates its entire software delivery lifecycle through GitHub Actions. All CI/CD configurations live in the `.github/workflows` directory, providing continuous integration, reproducible builds, error monitoring, and on-demand preview environments. This guide breaks down each pipeline, its triggers, and how they work together as derived directly from the source code.

---

## CI Workflow: ci.yml

The **ci.yml** workflow serves as the primary quality gate for every code change.

### Triggers and Purpose

- **Triggers**: `push` to `main` and any **pull request**
- **Key steps**: dependency installation, linting, type-checking, unit tests, Vite worker bundle build, and website compilation

The workflow uses `actions/setup-node@v4` with `cache: pnpm` for fast, reproducible dependency restoration. Concurrency is controlled via `group: ci-${{ github.ref }}`, automatically cancelling stale runs when new commits arrive.

### Core Pipeline Steps

```yaml

# From .github/workflows/ci.yml

# Simplified representation of the job structure

jobs:
  ci:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'pnpm'
      - run: pnpm install --frozen-lockfile
      - run: pnpm run ci:check      # Lint + type-check

      - run: pnpm run test:ci       # Unit test suite

      - run: pnpm vite build        # Worker bundle

      - run: pnpm --dir web install && pnpm --dir web run build

```

Run this locally to match CI behavior:

```bash
pnpm install --frozen-lockfile
pnpm run ci:check
pnpm run test:ci
pnpm vite build
pnpm --dir web install && pnpm --dir web run build

```

---

## Docker Image Build Workflow: docker-image.yml

The **docker-image.yml** workflow produces multi-architecture container images for self-hosting.

### Triggers and Publishing

- **Triggers**: `push` to `main`, `v*` tags, and **manual dispatch** via `workflow_dispatch`
- **Output**: GitHub Container Registry (GHCR)

This workflow builds for both `linux/amd64` and `linux/arm64` using QEMU and Buildx. The `docker/metadata-action@v5` auto-generates tags and labels, while `type=gha` cache acceleration speeds up subsequent builds.

### Multi-Arch Build Configuration

```yaml

# From .github/workflows/docker-image.yml

# Key Docker buildx configuration

- name: Set up QEMU
  uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
  uses: docker/setup-buildx-action@v3
- name: Build and push
  uses: docker/build-push-action@v5
  with:
    context: .
    file: Dockerfile.selfhost
    platforms: linux/amd64,linux/arm64
    cache-from: type=gha
    cache-to: type=gha,mode=max

```

Trigger manually with the GitHub CLI:

```bash
gh workflow run docker-image.yml --ref main

```

---

## Sourcemaps Upload Workflow: sourcemaps.yml

The **sourcemaps.yml** workflow ensures production errors remain debuggable.

### Purpose and Trigger

- **Trigger**: `push` to `main` only
- **Function**: Compile and upload sourcemaps to **PostHog** for error de-obfuscation

The workflow requires `POSTHOG_CLI_TOKEN` via `${{ secrets.POSTHOG_CLI_TOKEN }}`. This enables the team to trace minified production errors back to original TypeScript source locations.

---

## PR Preview Workflow: pr-preview.yml

The **pr-preview.yml** workflow creates ephemeral preview environments for every pull request on **Cloudflare Workers**.

### Full Lifecycle Automation

| PR Event | Action |
|----------|--------|
| `opened` | Deploy new preview stage |
| `synchronize` | Update existing preview with new commits |
| `reopened` | Redeploy previously closed preview |
| `closed` | Automatically destroy preview and clean up resources |

### Preview URL Generation and Verification

The workflow reads `WORKERS_SUBDOMAIN` from the `ENV_PREVIEW` secret (a `.env.preview` file) to construct URLs like `https://open-seo-pr-12.example.workers.dev`. After deployment, it validates that **Cloudflare Access** protection is active, then posts the preview URL as a PR comment.

Access the preview from the posted comment:

```bash

# Example URL from PR comment

curl -I https://open-seo-pr-12.example.workers.dev

```

---

## Shared Architecture Patterns

All four workflows in `.github/workflows` follow consistent design principles:

- **Concurrency control**: Each uses `concurrency` blocks with `cancel-in-progress: true` to prevent resource waste
- **Secret injection**: Sensitive credentials use `${{ secrets... }}` and `${{ vars... }}` contexts
- **Caching strategy**: pnpm dependencies and Docker layers are aggressively cached
- **Fail-fast behavior**: Quality checks run early to surface issues before expensive builds

---

## Summary

- **[`ci.yml`](https://github.com/every-app/open-seo/blob/main/ci.yml)** runs lint, type-check, tests, and builds on every push and PR
- **[`docker-image.yml`](https://github.com/every-app/open-seo/blob/main/docker-image.yml)** publishes multi-arch images to GHCR on main/tags or manual trigger
- **[`sourcemaps.yml`](https://github.com/every-app/open-seo/blob/main/sourcemaps.yml)** uploads production sourcemaps to PostHog after successful main branch builds
- **[`pr-preview.yml`](https://github.com/every-app/open-seo/blob/main/pr-preview.yml)** deploys and tears down Cloudflare Workers previews tied to PR lifecycle
- All workflows use **concurrency controls**, **strategic caching**, and **secret-based configuration** for secure, efficient automation

---

## Frequently Asked Questions

### How do I trigger a Docker build without pushing code?

Use the GitHub CLI or GitHub web UI to run the **docker-image.yml** workflow with `workflow_dispatch`. Run: `gh workflow run docker-image.yml --ref main`.

### What architectures does the Docker image support?

The **docker-image.yml** workflow builds for **linux/amd64** and **linux/arm64** using QEMU emulation and Docker Buildx, ensuring compatibility with most server environments.

### Where do PR preview URLs come from?

The **pr-preview.yml** workflow constructs URLs using the `WORKERS_SUBDOMAIN` value from the `ENV_PREVIEW` secret, producing addresses like `https://open-seo-pr-N.subdomain.workers.dev` and posting them as PR comments.

### Why are sourcemaps uploaded separately from the main CI?

Sourcemap generation requires production build artifacts and the **PostHog CLI token**. The **sourcemaps.yml** workflow isolates this concern, running only after successful main branch builds to ensure de-obfuscation data matches deployed code.