CI/CD Pipeline Configuration in open-seo: Complete GitHub Actions Guide
The open-seo repository uses four GitHub Actions workflows—CI, Docker image build, sourcemap upload, and PR preview—to automate testing, building, and deploying on every push and pull request.
This guide walks through the complete CI/CD pipeline configuration in open-seo, an open-source SEO tool built by every-app. Every workflow lives in .github/workflows and runs on GitHub Actions, providing a fully automated path from code commit to production deployment. Whether you are extending the project or adapting these patterns for your own repository, understanding the workflow architecture is essential.
Core CI Workflow: Testing and Validation
The CI workflow (ci.yml) serves as the entry point for all code changes. It triggers on every push to main and every pull request, ensuring that no broken code reaches the default branch.
The workflow performs the following sequence:
- Install dependencies using pnpm with frozen lockfile enforcement
- Run lint and type-check via
ci:check - Execute unit tests with
test:ci - Build the Vite-based worker bundle for the core application
- Compile the website from the
web/directory
Each step mirrors commands you can run locally:
pnpm install --frozen-lockfile
pnpm run ci:check
pnpm run test:ci
pnpm vite build
pnpm --dir web install && pnpm --dir web run build
The workflow uses actions/setup-node@v4 with cache: pnpm to speed up dependency installation across runs.
Docker Image Build: Multi-Architecture Publishing
The Docker workflow (docker-image.yml) produces reproducible container images for self-hosting. It triggers on pushes to main or any v* tag, plus manual dispatch via workflow_dispatch.
Key technical characteristics:
- Multi-architecture support using QEMU and Buildx for
linux/amd64andlinux/arm64 - GitHub Container Registry (GHCR) as the push target
- Docker build cache via
type=ghafor faster rebuilds - Automatic metadata generation with
docker/metadata-action@v5
The build uses Dockerfile.selfhost rather than the default Dockerfile, producing images tagged with both semantic versions and latest.
Trigger manually when needed:
gh workflow run docker-image.yml --ref main
Sourcemap Upload: Production Error Tracking
The sourcemaps workflow (sourcemaps.yml) runs exclusively on main branch pushes. It compiles JavaScript sourcemaps and uploads them to PostHog, enabling de-obfuscation of production stack traces.
This workflow requires the POSTHOG_CLI_TOKEN secret and executes after the main build completes. Sourcemaps bridge the gap between minified production code and readable source, making runtime error investigation practical.
PR Preview: On-Demand Staging Environments
The PR preview workflow (pr-preview.yml) deploys temporary staging environments on Cloudflare Workers for every pull request. It responds to opened, synchronize, reopened, and closed events.
Deployment lifecycle:
- Extract configuration from
ENV_PREVIEWsecret (contains.env.previewcontent includingWORKERS_SUBDOMAIN) - Deploy to Cloudflare Workers using Wrangler with a stage name derived from the PR number
- Verify Cloudflare Access protection is active on the preview URL
- Post PR comment with the preview URL for reviewer access
- Teardown on close when the PR is merged or abandoned
Access the preview from the comment:
# Posted comment format:
# **Preview deployed** (stage `pr-12`): https://open-seo-pr-12.example.workers.dev
curl -I https://open-seo-pr-12.example.workers.dev
Shared Workflow Architecture
All four workflows in open-seo share common architectural patterns that ensure reliability and performance.
Concurrency Control
Every workflow declares a concurrency block to prevent redundant runs:
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
This ensures only the latest run for any given branch or PR executes, automatically cancelling stale jobs.
Secrets and Environment Variables
Sensitive configuration flows through GitHub's secrets system:
POSTHOG_CLI_TOKEN: Sourcemap upload authenticationCLOUDFLARE_ACCOUNT_ID,CLOUDFLARE_API_TOKEN: Workers deployment credentialsENV_PREVIEW: Complete.env.previewfile for staging configuration
Non-sensitive values use ${{ vars... }} where appropriate.
Caching Strategy
Two caching layers accelerate the pipeline:
| Layer | Implementation | Benefit |
|---|---|---|
| Node dependencies | actions/setup-node@v4 with cache: pnpm |
~30-60s saved per run |
| Docker layers | type=gha Buildx cache |
Faster multi-arch builds |
Workflow File Reference
| File | Purpose | Trigger Events |
|---|---|---|
.github/workflows/ci.yml |
Install, lint, test, build | push to main, all PRs |
.github/workflows/docker-image.yml |
Multi-arch image build and push | push to main or v* tags, workflow_dispatch |
.github/workflows/sourcemaps.yml |
Build and upload PostHog sourcemaps | push to main |
.github/workflows/pr-preview.yml |
Deploy and manage PR staging environments | PR opened, synchronize, reopened, closed |
Summary
- Four workflows handle the complete CI/CD lifecycle in open-seo: CI validation, Docker publishing, sourcemap upload, and PR preview deployment
- Concurrency controls prevent redundant runs and race conditions across all workflows
- Multi-architecture Docker builds ensure images run on both AMD64 and ARM64 infrastructure
- Automated PR previews on Cloudflare Workers give reviewers live staging URLs without manual intervention
- Secrets-based configuration keeps credentials out of source code while enabling Cloudflare and PostHog integrations
Frequently Asked Questions
How do I run the CI checks locally before pushing?
Execute the same commands defined in ci.yml: pnpm install --frozen-lockfile, pnpm run ci:check, pnpm run test:ci, and the build commands for both the worker and website. This validates your changes without waiting for GitHub Actions.
What triggers a new Docker image build?
The Docker workflow runs automatically on any push to main or a version tag matching v*. You can also trigger it manually with gh workflow run docker-image.yml --ref main for testing or emergency rebuilds.
Where are the PR preview URLs posted?
The pr-preview.yml workflow automatically posts a comment on each pull request containing the deployed preview URL. The URL follows the pattern https://open-seo-pr-{NUMBER}.{SUBDOMAIN}.workers.dev derived from your WORKERS_SUBDOMAIN configuration.
Why does sourcemap upload only run on main branch pushes?
Sourcemaps are only needed for production error tracking, and production deployments originate from main. Running this on every PR would create unnecessary uploads and consume PostHog quota without providing value, since preview deployments use separate build configurations.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →