Skip to main content
Automate your Kodexa metadata deployments with kdx-sync-action v2 - a GitHub Action that makes GitOps workflows simple, secure, and reliable.
Philosophy: Branch determines deployment. One way to do it. Zero knobs, just config.

Quick Start

Deploy to Kodexa in 4 simple steps:

1. Define Branch Mappings

Create sync-config.yaml in your repository root:
metadata_dir: kodexa-metadata

# Branch determines deployment
branch_mappings:
  - pattern: "main"
    target: production
    environment: prod

  - pattern: "staging"
    target: staging
    environment: staging

  - pattern: "feature/*"
    target: development
    environment: dev

# Environments define API endpoints
environments:
  prod:
    url: https://platform.kodexa.com
    api_key_from_env: KODEXA_PROD_API_KEY

  staging:
    url: https://staging.kodexa.com
    api_key_from_env: KODEXA_STAGING_API_KEY

  dev:
    url: https://dev.kodexa.com
    api_key_from_env: KODEXA_DEV_API_KEY

# Targets define what gets deployed
targets:
  production:
    manifests:
      - organizations/acme-corp/manifest.yaml
      - organizations/acme-corp/modules/*/manifest.yaml

  staging:
    manifests:
      - organizations/acme-corp/manifest.yaml

  development:
    manifests:
      - organizations/acme-corp/manifest.yaml

2. Add Secrets

In GitHub repository settings → Secrets and variables → Actions:
  • KODEXA_PROD_API_KEY
  • KODEXA_STAGING_API_KEY
  • KODEXA_DEV_API_KEY
Use GitHub environments to add protection rules like required approvals for production deployments.

3. Create Workflow

Create .github/workflows/deploy.yml:
name: Deploy

on:
  push:
    branches: [main, staging, 'feature/**']

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

      - uses: kodexa-ai/kdx-sync-action@v2
        env:
          KODEXA_PROD_API_KEY: ${{ secrets.KODEXA_PROD_API_KEY }}
          KODEXA_STAGING_API_KEY: ${{ secrets.KODEXA_STAGING_API_KEY }}
          KODEXA_DEV_API_KEY: ${{ secrets.KODEXA_DEV_API_KEY }}

4. Push and Deploy

git add .
git commit -m "Configure automated deployments"
git push origin main
Done! Push to main → production. Push to feature/new-thing → dev. Branch determines deployment automatically.

Understanding the Action

The kdx-sync-action is a composite GitHub Action that:
  1. Detects your environment (OS and architecture)
  2. Downloads kdx CLI (latest or pinned version)
  3. Caches the binary (faster subsequent runs)
  4. Auto-discovers configuration (sync-config.yaml, metadata directory)
  5. Runs deployment (kdx sync deploy with appropriate flags)
  6. Parses results (extracts statistics and sets outputs)
You don’t need to:
  • Install kdx CLI manually
  • Handle OS/architecture detection
  • Manage binary caching
  • Parse deployment output
The action handles all of this automatically.

Action Inputs

All inputs are optional:
InputDescriptionRequiredDefault
sync-configPath to sync-config.yamlNoAuto-discovered
metadata-dirMetadata directory overrideNoAuto-discovered
dry-runPreview only (true/false)Nofalse
kdx-versionkdx-cli version to useNolatest

Example with Inputs

- uses: kodexa-ai/kdx-sync-action@v2
  with:
    sync-config: config/sync.yaml
    metadata-dir: resources
    kdx-version: v0.1.20
  env:
    KODEXA_PROD_API_KEY: ${{ secrets.KODEXA_PROD_API_KEY }}

Action Outputs

The action provides deployment statistics:
OutputDescription
targets-deployedNumber of targets deployed
resources-createdResources created
resources-updatedResources updated
resources-skippedResources unchanged

Using Outputs

- id: deploy
  uses: kodexa-ai/kdx-sync-action@v2
  env:
    KODEXA_PROD_API_KEY: ${{ secrets.KODEXA_PROD_API_KEY }}

- name: Show deployment summary
  run: |
    echo "Targets: ${{ steps.deploy.outputs.targets-deployed }}"
    echo "Created: ${{ steps.deploy.outputs.resources-created }}"
    echo "Updated: ${{ steps.deploy.outputs.resources-updated }}"
    echo "Skipped: ${{ steps.deploy.outputs.resources-skipped }}"

Complete Workflow Examples

Multi-Environment Deployment

The standard pattern - branch determines everything:
name: Deploy to Multiple Environments

on:
  push:
    branches: [main, staging, develop, 'feature/**']

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

      - uses: kodexa-ai/kdx-sync-action@v2
        env:
          KODEXA_PROD_API_KEY: ${{ secrets.KODEXA_PROD_API_KEY }}
          KODEXA_STAGING_API_KEY: ${{ secrets.KODEXA_STAGING_API_KEY }}
          KODEXA_DEV_API_KEY: ${{ secrets.KODEXA_DEV_API_KEY }}
With sync-config.yaml branch mappings:
branch_mappings:
  - pattern: "main"
    target: production
    environment: prod

  - pattern: "staging"
    target: staging
    environment: staging

  - pattern: "develop"
    target: development
    environment: dev

  - pattern: "feature/*"
    target: development
    environment: dev
No logic in the workflow! All routing is handled by sync-config.yaml.

Pull Request Validation with Preview

Validate changes and comment on PRs:
name: Validate PR

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

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

      - id: preview
        uses: kodexa-ai/kdx-sync-action@v2
        with:
          dry-run: true
        env:
          KODEXA_DEV_API_KEY: ${{ secrets.KODEXA_DEV_API_KEY }}

      - uses: actions/github-script@v7
        with:
          script: |
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: `## 🧪 Deployment Preview

              **Targets**: ${{ steps.preview.outputs.targets-deployed }}
              **Create**: ${{ steps.preview.outputs.resources-created }}
              **Update**: ${{ steps.preview.outputs.resources-updated }}
              **Skip**: ${{ steps.preview.outputs.resources-skipped }}

              ✅ Changes validated. Safe to merge.`
            });

Production with Required Approval

Require manual approval before production deployment:
name: Production Deployment

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production  # Requires approval in Settings → Environments
    steps:
      - uses: actions/checkout@v4

      - uses: kodexa-ai/kdx-sync-action@v2
        env:
          KODEXA_PROD_API_KEY: ${{ secrets.KODEXA_PROD_API_KEY }}
Setup required approvals:
  1. Go to Settings → Environments
  2. Create “production” environment
  3. Add required reviewers
  4. Optional: Add wait timer

Multi-Target Deployment

Deploy to multiple organizations:
# sync-config.yaml
branch_mappings:
  - pattern: "main"
    targets:
      - name: org-a-prod
        environment: prod
      - name: org-b-prod
        environment: prod

targets:
  org-a-prod:
    manifests: [organizations/org-a/manifest.yaml]
  org-b-prod:
    manifests: [organizations/org-b/manifest.yaml]
# .github/workflows/deploy.yml
name: Multi-Organization Deploy

on:
  push:
    branches: [main]

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

      - uses: kodexa-ai/kdx-sync-action@v2
        env:
          KODEXA_PROD_API_KEY: ${{ secrets.KODEXA_PROD_API_KEY }}
The action automatically deploys to both organizations based on branch mapping.

Scheduled Synchronization

Keep environments synchronized on a schedule:
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

      - uses: kodexa-ai/kdx-sync-action@v2
        env:
          KODEXA_PROD_API_KEY: ${{ secrets.KODEXA_PROD_API_KEY }}

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

Manual Deployment with Parameters

Manual trigger with workflow inputs:
name: Manual Deploy

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

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

      - id: deploy
        uses: kodexa-ai/kdx-sync-action@v2
        with:
          dry-run: ${{ github.event.inputs.dry-run }}
        env:
          KODEXA_DEV_API_KEY: ${{ secrets.KODEXA_DEV_API_KEY }}
          KODEXA_STAGING_API_KEY: ${{ secrets.KODEXA_STAGING_API_KEY }}
          KODEXA_PROD_API_KEY: ${{ secrets.KODEXA_PROD_API_KEY }}

      - name: Deployment 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' && 'Preview' || 'Live' }}" >> $GITHUB_STEP_SUMMARY
          echo "Targets: ${{ steps.deploy.outputs.targets-deployed }}" >> $GITHUB_STEP_SUMMARY
          echo "Created: ${{ steps.deploy.outputs.resources-created }}" >> $GITHUB_STEP_SUMMARY
          echo "Updated: ${{ steps.deploy.outputs.resources-updated }}" >> $GITHUB_STEP_SUMMARY

Migration from v1 to v2

What Changed

v1 (old): Manual environment logic in workflow
# Old - complex workflow with manual logic
- name: Determine environment
  run: |
    if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
      echo "url=${{ secrets.PROD_URL }}" >> $GITHUB_ENV
      echo "token=${{ secrets.PROD_TOKEN }}" >> $GITHUB_ENV
    elif [[ "${{ github.ref }}" == "refs/heads/staging" ]]; then
      echo "url=${{ secrets.STAGING_URL }}" >> $GITHUB_ENV
      echo "token=${{ secrets.STAGING_TOKEN }}" >> $GITHUB_ENV
    fi

- uses: kodexa-ai/kdx-sync-action@v1
  with:
    kodexa-url: ${{ env.url }}
    kodexa-token: ${{ env.token }}
v2 (new): Branch mappings in configuration
# New - simple workflow, logic in sync-config.yaml
- uses: kodexa-ai/kdx-sync-action@v2
  env:
    KODEXA_PROD_API_KEY: ${{ secrets.KODEXA_PROD_API_KEY }}
    KODEXA_STAGING_API_KEY: ${{ secrets.KODEXA_STAGING_API_KEY }}

Migration Steps

1

Move mappings to sync-config.yaml

Create branch mappings in your configuration:
branch_mappings:
  - pattern: "main"
    target: production
    environment: prod

  - pattern: "staging"
    target: staging
    environment: staging
2

Add environments to config

Define environments with API key references:
environments:
  prod:
    url: https://platform.kodexa.com
    api_key_from_env: KODEXA_PROD_API_KEY

  staging:
    url: https://staging.kodexa.com
    api_key_from_env: KODEXA_STAGING_API_KEY
3

Simplify workflow

Replace complex workflow logic:
# Remove all environment detection logic
# Replace with simple:
- uses: kodexa-ai/kdx-sync-action@v2
  env:
    KODEXA_PROD_API_KEY: ${{ secrets.KODEXA_PROD_API_KEY }}
    KODEXA_STAGING_API_KEY: ${{ secrets.KODEXA_STAGING_API_KEY }}
4

Update secrets

Replace old secret names with new format:
  • PROD_URL + PROD_TOKENKODEXA_PROD_API_KEY
  • STAGING_URL + STAGING_TOKENKODEXA_STAGING_API_KEY

Key Benefits of v2

  • Simpler workflows - No manual environment detection
  • Configuration-driven - Logic lives in sync-config.yaml
  • Less duplication - One workflow handles all branches
  • Easier maintenance - Change routing in config, not workflow
  • Auto-discovery - Finds sync-config.yaml automatically

Security Best Practices

1. Use GitHub Environment Secrets

Store API keys in environment-specific secrets:
jobs:
  deploy:
    environment: production  # Links to environment in repo settings
    steps:
      - uses: kodexa-ai/kdx-sync-action@v2
        env:
          KODEXA_PROD_API_KEY: ${{ secrets.KODEXA_PROD_API_KEY }}
Benefits:
  • Environment-specific secrets
  • Required approval rules
  • Wait timers
  • Deployment visibility
  • Complete audit trails

2. Never Hardcode Credentials

# ✅ Correct - reference secrets
env:
  KODEXA_PROD_API_KEY: ${{ secrets.KODEXA_PROD_API_KEY }}

# ❌ Never do this
env:
  KODEXA_PROD_API_KEY: "sk-abc123..."

3. Require Approvals for Production

Configure environment protection rules:
  1. Settings → Environments
  2. Select “production”
  3. Enable “Required reviewers”
  4. Add team members
  5. Optional: Add wait timer

4. Use Branch Protection

Protect critical branches:
  1. Settings → Branches
  2. Add protection rule for main
  3. Require pull request reviews
  4. Require status checks to pass
  5. Require branch to be up to date

5. Limit Workflow Permissions

Use minimal necessary permissions:
permissions:
  contents: read  # Read repository contents
  pull-requests: write  # Comment on PRs (for validation workflow)

6. Validate Before Deploying

Always use dry-run on PRs:
on: pull_request

- uses: kodexa-ai/kdx-sync-action@v2
  with:
    dry-run: true

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/data-definitions/new-taxonomy.yaml

# Update manifest if needed
vim manifests/main.yaml
3

Test locally

# Set environment variables
export KODEXA_DEV_API_KEY="your-dev-key"

# Preview changes
kdx sync deploy --dry-run
4

Commit and push

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

Open pull request

  • GitHub automatically runs dry-run validation
  • Review deployment preview in PR comments
  • Request team review
6

Merge and deploy

  • After approval, merge PR
  • GitHub Actions automatically deploys based on branch
  • Monitor workflow logs for results

Advanced: Using Manual kdx CLI

For most GitHub Actions use cases, use kdx-sync-action. Manual CLI is for local development and advanced debugging.

When to Use Manual CLI

  • Local development - Testing changes before committing
  • Advanced debugging - Need detailed control and output
  • Custom CI systems - Not using GitHub Actions
  • One-off operations - Manual syncs or migrations

Manual Installation in Workflows

If you need to use kdx CLI directly:
steps:
  - uses: actions/checkout@v4

  - name: Install KDX CLI
    run: |
      # Download latest release
      curl -sL https://github.com/kodexa-ai/kdx-cli-releases/releases/latest/download/kdx_linux_x86_64.tar.gz | tar xz
      sudo mv kdx /usr/local/bin/

  - name: Deploy
    env:
      KODEXA_PROD_API_KEY: ${{ secrets.KODEXA_PROD_API_KEY }}
    run: |
      kdx sync deploy --confirm-all
Note: kdx-sync-action handles all of this automatically with caching and cross-platform support.

Troubleshooting

Binary Download Failed

Issue: “Failed to download kdx from …” Solution: Specify a specific version:
- uses: kodexa-ai/kdx-sync-action@v2
  with:
    kdx-version: "v0.1.20"
Check available releases at kdx-cli-releases.

Branch Mapping Not Found

Issue: “No branch mapping found for branch ‘feature/xyz’” Solution 1 - Add fallback mapping:
branch_mappings:
  - pattern: "*"  # Fallback for any branch
    target: development
    environment: dev
Solution 2 - Use manual override in workflow:
- uses: kodexa-ai/kdx-sync-action@v2
  with:
    # Override auto-detection
    # (But this defeats the purpose of branch mappings)
  env:
    KODEXA_DEV_API_KEY: ${{ secrets.KODEXA_DEV_API_KEY }}
  # Then use: kdx sync deploy --target dev --env development

Environment Variable Not Set

Issue: “Environment variable KODEXA_PROD_API_KEY not set” Fix: Ensure secret exists and is passed to action:
- uses: kodexa-ai/kdx-sync-action@v2
  env:
    KODEXA_PROD_API_KEY: ${{ secrets.KODEXA_PROD_API_KEY }}
Verify secret:
  1. Settings → Secrets and variables → Actions
  2. Confirm secret name matches exactly
  3. Check environment restrictions if using GitHub environments

Authentication Failed

Issue: “Authentication failed” or “Invalid API key” Solutions:
  1. Verify secret value - Regenerate API key if needed
  2. Check key permissions - Ensure key has deployment access
  3. Test manually:
    curl -H "Authorization: Bearer YOUR_API_KEY" \
      https://platform.kodexa.com/api/workspaces
    

Deployment Validation Passed but Deployment Failed

Issue: Dry-run succeeds, but live deployment fails Common causes:
  • Resource dependencies don’t exist in target environment
  • Insufficient API key permissions
  • Environment-specific differences
Solution: Review error details in workflow logs and check resource dependencies.

Best Practices

1. Use Dry-Run on Pull Requests

Always validate before merging:
on: pull_request

- uses: kodexa-ai/kdx-sync-action@v2
  with:
    dry-run: true

2. Use GitHub Environments for Protection

Separate credentials and add approval rules:
jobs:
  deploy:
    environment: production  # Requires approval

3. Add Deployment Summaries

Make results visible in workflow summaries:
- id: deploy
  uses: kodexa-ai/kdx-sync-action@v2

- run: |
    echo "## Deployment" >> $GITHUB_STEP_SUMMARY
    echo "Targets: ${{ steps.deploy.outputs.targets-deployed }}" >> $GITHUB_STEP_SUMMARY
    echo "Created: ${{ steps.deploy.outputs.resources-created }}" >> $GITHUB_STEP_SUMMARY

4. Monitor Workflows

Set up notifications for failures:
- name: Notify on failure
  if: failure()
  # Add Slack/email notification

5. Document Your Configuration

Add comments to sync-config.yaml:
# Production deployment - requires approval
- pattern: "main"
  target: production
  environment: prod

6. Version Pin for Stability

Pin kdx-version for production workflows:
- uses: kodexa-ai/kdx-sync-action@v2
  with:
    kdx-version: "v0.1.20"  # Explicit version

7. Test Branch Mappings Locally

Before committing configuration:
# See which branch mapping matches
git branch --show-current
kdx sync deploy --dry-run

Next Steps