# How to Configure GitHub Workflows in the `.github` Directory for Open‑SEO

> Configure Open-SEO GitHub workflows easily. Learn to set up CI/CD and testing by creating YAML files in the .github/workflows directory for efficient automation.

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

---

**To configure workflows in the `.github` directory for Open‑SEO, create YAML files under `.github/workflows/` that define triggers, jobs, and steps for continuous integration, testing, and deployment.**

The **open-seo** repository by **every-app** uses GitHub Actions to automate its development pipeline. All workflow configurations reside in the hidden `.github/workflows/` directory, following the standard GitHub Actions convention. This guide covers the existing workflows, how to create new ones, and best practices specific to this project.

## Understanding the `.github/workflows/` Directory Structure

GitHub Actions requires workflow files to live in `.github/workflows/` at the repository root. Each `.yml` file represents an independent workflow that GitHub executes based on its configured triggers.

The **open-seo** repository includes the following established workflows:

| Workflow File | Purpose | Trigger Events |
|-------------|---------|--------------|
| [`ci.yml`](https://github.com/every-app/open-seo/blob/main/ci.yml) | Linting, type‑checking, unit tests, and builds | `push` and `pull_request` to `main` |
| [`e2e.yml`](https://github.com/every-app/open-seo/blob/main/e2e.yml) | Playwright end‑to‑end tests | Manual or scheduled runs |
| [`publish.yml`](https://github.com/every-app/open-seo/blob/main/publish.yml) | Deploys Cloudflare Workers | New Git tags |
| [`release.yml`](https://github.com/every-app/open-seo/blob/main/release.yml) | Generates GitHub Releases with changelogs | Tag creation |

## Anatomy of a Workflow File

Every workflow in **open-seo** follows a consistent structure. Below is the foundational pattern used across the project:

```yaml
name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    
    services:
      postgres:
        image: postgres:15
        env:
          POSTGRES_USER: postgres
          POSTGRES_PASSWORD: postgres
          POSTGRES_DB: open_seo
        ports: [5432:5432]
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

    steps:
      - uses: actions/checkout@v3
      
      - name: Set up Node
        uses: actions/setup-node@v3
        with:
          node-version: 20
          
      - name: Install dependencies
        run: npm ci
        
      - name: Lint
        run: npm run lint
        
      - name: Type check
        run: npm run typecheck
        
      - name: Unit tests
        run: npm test -- --runInBand

```

Key components to understand:

- **`name`** — Display title shown in GitHub's Actions tab
- **`on`** — Event triggers (`push`, `pull_request`, `schedule`, `workflow_dispatch`)
- **`jobs`** — Parallel or sequential execution units
- **`runs-on`** — Virtual machine environment (Ubuntu latest for **open-seo**)
- **`services`** — Docker containers accessible to the job (PostgreSQL for database tests)
- **`steps`** — Individual commands or actions executed in sequence

## Creating a New Workflow in Open‑SEO

Follow this process to add custom automation to the **open-seo** project:

### Step 1: Create the Workflow Directory

If `.github/workflows/` does not exist, create it:

```bash
mkdir -p .github/workflows

```

### Step 2: Add a New YAML File

Name files descriptively with the `.yml` extension. Examples from **open-seo**:
- [`ci.yml`](https://github.com/every-app/open-seo/blob/main/ci.yml) for continuous integration
- [`e2e.yml`](https://github.com/every-app/open-seo/blob/main/e2e.yml) for browser testing
- [`publish.yml`](https://github.com/every-app/open-seo/blob/main/publish.yml) for deployment
- [`release.yml`](https://github.com/every-app/open-seo/blob/main/release.yml) for release automation

### Step 3: Define Your Trigger

Common patterns in **open-seo**:

```yaml

# Run on every push to main and all pull requests

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

# Or schedule a nightly job

on:
  schedule:
    - cron: '0 2 * * *'  # 2:00 AM UTC daily

# Or manual trigger only

on: workflow_dispatch

```

### Step 4: Configure Environment and Dependencies

Standard setup for **open-seo** Node.js projects:

```yaml
jobs:
  my-job:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v3
      
      - name: Set up Node
        uses: actions/setup-node@v3
        with:
          node-version: 20
          
      - name: Cache dependencies
        uses: actions/cache@v3
        with:
          path: ~/.npm
          key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
          
      - name: Install dependencies
        run: npm ci

```

### Step 5: Execute Your Tasks

Add steps that run **open-seo** npm scripts:

```yaml
      - name: Run custom audit
        run: npm run audit
        env:
          DATAFORSEO_API_KEY: ${{ secrets.DATAFORSEO_API_KEY }}

```

### Step 6: Upload Artifacts (Optional)

Preserve build outputs or reports:

```yaml
      - name: Upload results
        uses: actions/upload-artifact@v3
        with:
          name: audit-report
          path: ./audit-report.json

```

## Complete Example: Custom Nightly Audit Workflow

This practical example demonstrates how to configure workflows in the `.github` directory for **open-seo** to run automated SEO audits on a schedule:

```yaml

# .github/workflows/nightly-audit.yml

name: Nightly Site Audit

on:
  schedule:
    - cron: '30 3 * * *'  # 3:30 AM UTC daily

  workflow_dispatch:  # Allows manual trigger

jobs:
  audit:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v3
      
      - name: Set up Node
        uses: actions/setup-node@v3
        with:
          node-version: 20
          
      - name: Install dependencies
        run: npm ci
        
      - name: Run site audit
        env:
          DATAFORSEO_API_KEY: ${{ secrets.DATAFORSEO_API_KEY }}
        run: npm run audit
        
      - name: Upload audit report
        uses: actions/upload-artifact@v3
        with:
          name: audit-report
          path: ./audit-report.json
          retention-days: 30

```

## Managing Secrets for Open‑SEO Workflows

Sensitive configuration requires repository secrets. The **open-seo** project uses **DATAFORSEO_API_KEY** and potentially database credentials.

Configure secrets at **Settings → Secrets and variables → Actions**:

```yaml

# Reference secrets in workflow files

env:
  DATAFORSEO_API_KEY: ${{ secrets.DATAFORSEO_API_KEY }}
  DATABASE_URL: ${{ secrets.DATABASE_URL }}

```

Never commit secrets directly to `.github/workflows/` files.

## Performance Optimization Tips

Based on patterns in **open-seo** workflows:

- **Use dependency caching** — Include [`package-lock.json`](https://github.com/every-app/open-seo/blob/main/package-lock.json) in cache keys to prevent stale dependencies
- **Leverage service containers** — PostgreSQL in [`ci.yml`](https://github.com/every-app/open-seo/blob/main/ci.yml) demonstrates testing against real databases
- **Conditional job execution** — Expensive jobs should check `github.event_name` and `github.base_ref`
- **Matrix builds** — Test across Node versions using `strategy.matrix` for broader compatibility

## Troubleshooting Common Issues

| Symptom | Solution |
|---------|----------|
| Workflow not appearing | Verify file is in `.github/workflows/` with `.yml` extension |
| Secret undefined errors | Confirm secret is set in repository settings, not just organization |
| Database connection failures | Check service port mapping (5432 for PostgreSQL) and health checks |
| Stale dependencies | Invalidate cache by updating [`package-lock.json`](https://github.com/every-app/open-seo/blob/main/package-lock.json) or changing cache key |
| Permission denied on publish | Verify `GITHUB_TOKEN` permissions or use personal access token |

## Summary

- **All workflows belong in `.github/workflows/`** as YAML files per GitHub Actions specification
- **open-seo** provides four reference implementations: [`ci.yml`](https://github.com/every-app/open-seo/blob/main/ci.yml), [`e2e.yml`](https://github.com/every-app/open-seo/blob/main/e2e.yml), [`publish.yml`](https://github.com/every-app/open-seo/blob/main/publish.yml), and [`release.yml`](https://github.com/every-app/open-seo/blob/main/release.yml)
- **Triggers** range from push events to scheduled cron jobs and manual dispatch
- **Service containers** enable integration testing with PostgreSQL and other dependencies
- **Secrets management** separates sensitive configuration from version-controlled workflow files
- **Caching and artifact upload** improve performance and enable result inspection

## Frequently Asked Questions

### Where exactly do workflow files go in the open-seo repository?

Workflow files must reside in `.github/workflows/` at the repository root. Each `.yml` file in this directory becomes an active workflow. The **open-seo** project organizes its automation in this location with files like [`ci.yml`](https://github.com/every-app/open-seo/blob/main/ci.yml), [`e2e.yml`](https://github.com/every-app/open-seo/blob/main/e2e.yml), [`publish.yml`](https://github.com/every-app/open-seo/blob/main/publish.yml), and [`release.yml`](https://github.com/every-app/open-seo/blob/main/release.yml).

### How do I trigger a workflow manually in open-seo?

Add `workflow_dispatch:` to your `on:` block. This creates a "Run workflow" button in the GitHub Actions tab. The **open-seo** [`nightly-audit.yml`](https://github.com/every-app/open-seo/blob/main/nightly-audit.yml) example demonstrates combining scheduled and manual triggers for maximum flexibility.

### What Node.js version does open-seo use in its workflows?

The **open-seo** workflows specify **Node.js 20** in `actions/setup-node@v3`. This version is consistent across [`ci.yml`](https://github.com/every-app/open-seo/blob/main/ci.yml), [`publish.yml`](https://github.com/every-app/open-seo/blob/main/publish.yml), and other automation files. Update the `node-version` field in your workflows when the project migrates to newer releases.

### Can I use the existing open-seo workflows as templates?

Yes. Copy any file from `.github/workflows/` as a starting point. The [`ci.yml`](https://github.com/every-app/open-seo/blob/main/ci.yml) workflow provides the most comprehensive template, demonstrating service containers, caching, multi-step jobs, and artifact handling specific to the **open-seo** project structure.