Skip to main content
Automate your Kodexa metadata deployments with the kdx-sync-action - a GitHub Action that makes GitOps workflows simple, secure, and reliable.
This guide uses the kdx-sync-action which handles CLI installation, authentication, and sync operations automatically.

Quick Start

1. Create Sync Configuration

Create a sync-config.yaml in your repository:
# kodexa-metadata/sync-config.yaml
metadata_dir: kodexa-metadata

organizations:
  - slug: my-organization
    resources:
      - type: taxonomy
        slug: document-classification
      - type: store
        slug: document-store
      - type: featureType
        slug: text-extraction

2. Add Secrets to GitHub

In your repository settings, add:
  • KODEXA_URL - Your Kodexa platform URL (e.g., https://platform.kodexa.com)
  • KODEXA_TOKEN - Your Kodexa API token
For multiple environments, use environment-specific secrets like KODEXA_PROD_URL, KODEXA_STAGING_URL, etc.

3. Create Deployment Workflow

# .github/workflows/deploy.yml
name: Deploy to Kodexa

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Deploy to Kodexa
        uses: kodexa-ai/kdx-sync-action@v1
        with:
          kodexa-url: ${{ secrets.KODEXA_URL }}
          kodexa-token: ${{ secrets.KODEXA_TOKEN }}
That’s it! Every push to main will now automatically sync to Kodexa.

Complete Workflows

Multi-Environment Deployment

Deploy different branches to different environments:
# .github/workflows/multi-environment.yml
name: Multi-Environment Deploy

on:
  push:
    branches:
      - main       # Production
      - staging    # Staging
      - develop    # Development

jobs:
  determine-environment:
    runs-on: ubuntu-latest
    outputs:
      environment: ${{ steps.set-env.outputs.environment }}
    steps:
      - name: Determine environment
        id: set-env
        run: |
          case "${{ github.ref }}" in
            refs/heads/main)
              echo "environment=production" >> $GITHUB_OUTPUT
              ;;
            refs/heads/staging)
              echo "environment=staging" >> $GITHUB_OUTPUT
              ;;
            *)
              echo "environment=development" >> $GITHUB_OUTPUT
              ;;
          esac

  deploy:
    needs: determine-environment
    runs-on: ubuntu-latest
    environment: ${{ needs.determine-environment.outputs.environment }}
    steps:
      - uses: actions/checkout@v4

      - name: Sync to ${{ needs.determine-environment.outputs.environment }}
        uses: kodexa-ai/kdx-sync-action@v1
        with:
          kodexa-url: ${{ secrets.KODEXA_URL }}
          kodexa-token: ${{ secrets.KODEXA_TOKEN }}
GitHub environments allow you to add protection rules like required approvals before production deployments.

Pull Request Validation

Validate changes before they merge:
# .github/workflows/pr-validation.yml
name: Validate Changes

on:
  pull_request:
    paths:
      - 'kodexa-metadata/**'
      - 'sync-config.yaml'

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Dry-run sync
        id: validate
        uses: kodexa-ai/kdx-sync-action@v1
        with:
          kodexa-url: ${{ secrets.KODEXA_URL }}
          kodexa-token: ${{ secrets.KODEXA_TOKEN }}
          dry-run: true

      - name: Comment on PR
        uses: actions/github-script@v7
        with:
          script: |
            const body = `### 🧪 Sync Validation

            **Organizations:** ${{ steps.validate.outputs.organizations }}
            **Resources to create:** ${{ steps.validate.outputs.resources-created }}
            **Resources to update:** ${{ steps.validate.outputs.resources-updated }}
            **Resources unchanged:** ${{ steps.validate.outputs.resources-skipped }}

            ✅ Validation passed! Merging this PR will sync these changes.`;

            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: body
            });

Manual Deployment with Approval

Require manual trigger and approval:
# .github/workflows/manual-deploy.yml
name: Manual Deploy

on:
  workflow_dispatch:
    inputs:
      environment:
        description: 'Target environment'
        required: true
        type: choice
        options:
          - development
          - staging
          - production
      dry-run:
        description: 'Preview only (no changes)'
        type: boolean
        default: false

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: ${{ github.event.inputs.environment }}
    steps:
      - uses: actions/checkout@v4

      - name: Deploy to ${{ github.event.inputs.environment }}
        uses: kodexa-ai/kdx-sync-action@v1
        with:
          kodexa-url: ${{ secrets.KODEXA_URL }}
          kodexa-token: ${{ secrets.KODEXA_TOKEN }}
          dry-run: ${{ github.event.inputs.dry-run }}

      - name: Create summary
        run: |
          echo "## Deployment Summary" >> $GITHUB_STEP_SUMMARY
          echo "Environment: ${{ github.event.inputs.environment }}" >> $GITHUB_STEP_SUMMARY
          echo "Mode: ${{ github.event.inputs.dry-run == 'true' && 'Dry Run' || 'Live' }}" >> $GITHUB_STEP_SUMMARY

Scheduled Sync

Keep environments synchronized on a schedule:
# .github/workflows/scheduled-sync.yml
name: Scheduled Sync

on:
  schedule:
    - cron: '0 2 * * *'  # Daily at 2 AM UTC
  workflow_dispatch:     # Allow manual triggers

jobs:
  sync:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Sync to Kodexa
        uses: kodexa-ai/kdx-sync-action@v1
        with:
          kodexa-url: ${{ secrets.KODEXA_URL }}
          kodexa-token: ${{ secrets.KODEXA_TOKEN }}

      - name: Notify on failure
        if: failure()
        run: |
          echo "Sync failed at $(date)"
          # Add notification logic (Slack, email, etc.)

Action Inputs

The kdx-sync-action supports these inputs:
InputDescriptionRequiredDefault
kodexa-urlKodexa platform URL✅ Yes-
kodexa-tokenAPI authentication token✅ Yes-
sync-configPath to sync-config.yaml❌ NoAuto-discovered
metadata-dirMetadata directory❌ NoAuto-discovered
dry-runPreview changes only❌ Nofalse
kdx-versionkdx CLI version❌ Nolatest
organizationFilter by organization❌ No-
projectFilter by project❌ No-

Action Outputs

Access sync statistics in subsequent steps:
- name: Sync to Kodexa
  id: sync
  uses: kodexa-ai/kdx-sync-action@v1
  with:
    kodexa-url: ${{ secrets.KODEXA_URL }}
    kodexa-token: ${{ secrets.KODEXA_TOKEN }}

- name: Report results
  run: |
    echo "Organizations: ${{ steps.sync.outputs.organizations }}"
    echo "Created: ${{ steps.sync.outputs.resources-created }}"
    echo "Updated: ${{ steps.sync.outputs.resources-updated }}"
    echo "Skipped: ${{ steps.sync.outputs.resources-skipped }}"

Filtering Deployments

By Organization

- uses: kodexa-ai/kdx-sync-action@v1
  with:
    kodexa-url: ${{ secrets.KODEXA_URL }}
    kodexa-token: ${{ secrets.KODEXA_TOKEN }}
    organization: my-org  # Only sync this organization

By Project

- uses: kodexa-ai/kdx-sync-action@v1
  with:
    kodexa-url: ${{ secrets.KODEXA_URL }}
    kodexa-token: ${{ secrets.KODEXA_TOKEN }}
    project: my-org/project1  # Only sync this project

Multiple Filters

- uses: kodexa-ai/kdx-sync-action@v1
  with:
    kodexa-url: ${{ secrets.KODEXA_URL }}
    kodexa-token: ${{ secrets.KODEXA_TOKEN }}
    organization: org1,org2  # Multiple organizations
    project: org1/proj1,org2/proj2  # Multiple projects

Security Best Practices

1. Use GitHub Secrets

Never hardcode credentials:
# ✅ Correct
with:
  kodexa-url: ${{ secrets.KODEXA_URL }}
  kodexa-token: ${{ secrets.KODEXA_TOKEN }}

# ❌ Never do this
with:
  kodexa-url: "https://platform.kodexa.com"
  kodexa-token: "my-api-key-12345"

2. Use Environment Secrets

For multiple environments, leverage GitHub environment secrets:
jobs:
  deploy:
    environment: production  # Links to 'production' environment
    steps:
      - uses: kodexa-ai/kdx-sync-action@v1
        with:
          kodexa-url: ${{ secrets.KODEXA_URL }}      # From production environment
          kodexa-token: ${{ secrets.KODEXA_TOKEN }}  # From production environment

3. Require Approvals for Production

Configure environment protection rules in GitHub:
  1. Go to Settings → Environments
  2. Select “production”
  3. Enable “Required reviewers”
  4. Add team members who can approve

4. Use Branch Protection

Protect critical branches:
  1. Settings → Branches → Branch protection rules
  2. Protect main branch
  3. Require pull request reviews
  4. Require status checks to pass

Development Workflow

Step-by-Step Process

1

Create Feature Branch

git checkout -b feature/add-new-taxonomy
2

Make Changes

# Add or modify resources
vim kodexa-metadata/my-org/taxonomies/new-classification.yaml
3

Test Locally (Optional)

# Install kdx CLI locally
brew install kodexa-ai/tap/kdx

# Dry-run locally
kdx sync push --dry-run
4

Commit and Push

git add .
git commit -m "feat: add new document classification taxonomy"
git push origin feature/add-new-taxonomy
5

Open Pull Request

  • GitHub will automatically run validation
  • Review the dry-run results in PR comments
  • Request team review
6

Merge and Deploy

  • After approval, merge PR
  • GitHub Actions automatically deploys to target environment
  • Monitor workflow logs

Troubleshooting

Action fails with “Failed to download kdx”

Cause: Network connectivity or version issue Fix:
with:
  kdx-version: "v1.0.0"  # Specify explicit version

Authentication errors

Cause: Invalid or expired token Fix:
  1. Verify KODEXA_TOKEN secret is correct
  2. Check token hasn’t expired
  3. Ensure token has appropriate permissions

Config file not found

Cause: sync-config.yaml missing or wrong path Fix:
with:
  sync-config: kodexa-metadata/sync-config.yaml  # Explicit path

Dry-run passes but push fails

Cause: Resource references or permissions Fix:
  1. Check resource dependencies exist
  2. Verify API token has write permissions
  3. Review kdx CLI logs in workflow output

Best Practices

1. Always Use Dry-Run on PRs

Validate before merging:
on: pull_request
# ... with dry-run: true

2. Separate Workflows

Keep concerns separated:
  • deploy.yml - Automated deployments
  • pr-validation.yml - PR validation
  • manual-deploy.yml - Manual triggers

3. Add Deployment Summaries

Make results visible:
- name: Create summary
  run: |
    cat >> $GITHUB_STEP_SUMMARY << EOF
    ## Deployment Results
    - Organizations: ${{ steps.sync.outputs.organizations }}
    - Created: ${{ steps.sync.outputs.resources-created }}
    - Updated: ${{ steps.sync.outputs.resources-updated }}
    EOF

4. Monitor Workflows

Set up notifications for failures:
- name: Notify on failure
  if: failure()
  uses: slack-github-action@v1
  with:
    payload: |
      {
        "text": "Kodexa sync failed: ${{ github.event.head_commit.message }}"
      }

5. Document Your Workflows

Add comments to workflows:
# This workflow deploys to production on every push to main
# It requires manual approval via GitHub environment protection
name: Production Deploy

Advanced Patterns

Matrix Deployments

Deploy to multiple environments in parallel:
jobs:
  deploy:
    strategy:
      matrix:
        environment: [dev, staging, prod]
    environment: ${{ matrix.environment }}
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: kodexa-ai/kdx-sync-action@v1
        with:
          kodexa-url: ${{ secrets.KODEXA_URL }}
          kodexa-token: ${{ secrets.KODEXA_TOKEN }}

Conditional Deployments

Deploy based on file changes:
on:
  push:
    paths:
      - 'kodexa-metadata/**'  # Only when metadata changes

Rollback Workflow

Quick rollback to previous version:
name: Rollback

on:
  workflow_dispatch:
    inputs:
      commit:
        description: 'Commit SHA to rollback to'
        required: true

jobs:
  rollback:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.inputs.commit }}

      - uses: kodexa-ai/kdx-sync-action@v1
        with:
          kodexa-url: ${{ secrets.KODEXA_URL }}
          kodexa-token: ${{ secrets.KODEXA_TOKEN }}

Next Steps