---
title: CI/CD Integration
description: Automate documentation deployments with GitHub Actions, GitLab CI, and other CI/CD platforms.
icon: git-branch
---

# CI/CD Integration

Automate your documentation deployments with continuous integration. This guide covers setup for popular CI/CD platforms.

<Note>
**Connected a GitHub repo via the dashboard?** You may not need CI at all. Projects linked through the Syntext GitHub App rebuild automatically on every push to the configured branch, and pull requests get preview builds — no workflow file required. The setups below are for repos without the App, or for pipelines that need extra steps (tests, codegen) before deploying.
</Note>

## GitHub Actions

The recommended approach for GitHub-hosted repositories.

### Basic Workflow

Create `.github/workflows/docs.yml`:

```yaml
name: Deploy Docs

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

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Bun
        uses: oven-sh/setup-bun@v1
      
      - name: Install Syntext CLI
        run: curl -fsSL https://get.syntext.dev | sh
      
      - name: Deploy
        run: |
          if [ "${{ github.event_name }}" = "pull_request" ]; then
            stx deploy --preview
          else
            stx deploy
          fi
        env:
          SYNTEXT_API_KEY: ${{ secrets.SYNTEXT_API_KEY }}
```

### With Caching

Speed up builds with dependency caching:

```yaml
- name: Cache Syntext
  uses: actions/cache@v3
  with:
    path: ~/.syntext
    key: syntext-${{ runner.os }}-${{ hashFiles('syntext.json') }}
    restore-keys: |
      syntext-${{ runner.os }}-

- name: Cache Build
  uses: actions/cache@v3
  with:
    path: .syntext/cache
    key: build-${{ hashFiles('docs/**', 'syntext.json') }}
```

### PR Preview Comments

Add preview URLs as PR comments:

```yaml
- name: Deploy Preview
  id: preview
  if: github.event_name == 'pull_request'
  run: |
    URL=$(stx deploy --preview --json | jq -r '.url')
    echo "url=$URL" >> $GITHUB_OUTPUT
  env:
    SYNTEXT_API_KEY: ${{ secrets.SYNTEXT_API_KEY }}

- name: Comment PR
  if: github.event_name == 'pull_request'
  uses: actions/github-script@v6
  with:
    script: |
      github.rest.issues.createComment({
        issue_number: context.issue.number,
        owner: context.repo.owner,
        repo: context.repo.repo,
        body: '📚 Docs preview: ${{ steps.preview.outputs.url }}'
      })
```

## GitLab CI

Create `.gitlab-ci.yml`:

```yaml
stages:
  - deploy

deploy_docs:
  stage: deploy
  image: oven/bun:latest
  script:
    - curl -fsSL https://get.syntext.dev | sh
    - |
      if [ "$CI_PIPELINE_SOURCE" = "merge_request_event" ]; then
        stx deploy --preview --branch "$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME"
      else
        stx deploy
      fi
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
  variables:
    SYNTEXT_API_KEY: $SYNTEXT_API_KEY
```

### With Caching

```yaml
deploy_docs:
  cache:
    key: syntext-cache
    paths:
      - .syntext/cache
      - ~/.syntext
```

## Bitbucket Pipelines

Create `bitbucket-pipelines.yml`:

```yaml
image: oven/bun:latest

pipelines:
  branches:
    main:
      - step:
          name: Deploy Docs
          script:
            - curl -fsSL https://get.syntext.dev | sh
            - stx deploy
          caches:
            - syntext

  pull-requests:
    '**':
      - step:
          name: Preview Docs
          script:
            - curl -fsSL https://get.syntext.dev | sh
            - stx deploy --preview

definitions:
  caches:
    syntext: ~/.syntext
```

## CircleCI

Create `.circleci/config.yml`:

```yaml
version: 2.1

jobs:
  deploy:
    docker:
      - image: oven/bun:latest
    steps:
      - checkout
      - run:
          name: Install Syntext
          command: curl -fsSL https://get.syntext.dev | sh
      - run:
          name: Deploy
          command: stx deploy

workflows:
  deploy-docs:
    jobs:
      - deploy:
          filters:
            branches:
              only: main
```

## Environment Variables

### Required

| Variable | Description |
|----------|-------------|
| `SYNTEXT_API_KEY` | API key for authentication |

### Optional

| Variable | Description |
|----------|-------------|
| `SYNTEXT_PROJECT_ID` | Override project ID |
| `SYNTEXT_ENV` | `production` or `staging` |

### Getting Your API Key

1. Go to [Syntext Dashboard](https://syntext.dev/dashboard)
2. Navigate to **Settings** → **API Keys**
3. Click **Generate New Key**
4. Copy the key (shown only once)

<Warning>
Never commit API keys to your repository. Always use environment variables or secrets managers.
</Warning>

## Monorepo Setup

For monorepos with docs in a subdirectory:

```yaml
# GitHub Actions
- name: Deploy Docs
  working-directory: ./packages/docs
  run: stx deploy
```

Or with path filtering:

```yaml
on:
  push:
    branches: [main]
    paths:
      - 'docs/**'
      - 'packages/docs/**'
```

## Conditional Deployment

Deploy only when docs change:

```yaml
- name: Check for docs changes
  id: changes
  run: |
    if git diff --name-only HEAD~1 | grep -E '^docs/|syntext\.config\.json'; then
      echo "deploy=true" >> $GITHUB_OUTPUT
    fi

- name: Deploy
  if: steps.changes.outputs.deploy == 'true'
  run: stx deploy
```

## Deployment Status

Check deployment status programmatically:

```bash
stx status --json
```

Returns:

```json
{
  "project": "my-docs",
  "status": "live",
  "url": "https://my-docs-docs.syntext.dev",
  "lastDeployment": "2024-01-15T12:34:56Z"
}
```
