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:
- Detects your environment (OS and architecture)
- Downloads kdx CLI (latest or pinned version)
- Caches the binary (faster subsequent runs)
- Auto-discovers configuration (sync-config.yaml, metadata directory)
- Runs deployment (kdx sync deploy with appropriate flags)
- 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.
All inputs are optional:
| Input | Description | Required | Default |
|---|
sync-config | Path to sync-config.yaml | No | Auto-discovered |
metadata-dir | Metadata directory override | No | Auto-discovered |
dry-run | Preview only (true/false) | No | false |
kdx-version | kdx-cli version to use | No | latest |
- 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:
| Output | Description |
|---|
targets-deployed | Number of targets deployed |
resources-created | Resources created |
resources-updated | Resources updated |
resources-skipped | Resources 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:
- Go to Settings → Environments
- Create “production” environment
- Add required reviewers
- 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
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
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
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 }}
Update secrets
Replace old secret names with new format:
PROD_URL + PROD_TOKEN → KODEXA_PROD_API_KEY
STAGING_URL + STAGING_TOKEN → KODEXA_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:
- Settings → Environments
- Select “production”
- Enable “Required reviewers”
- Add team members
- Optional: Add wait timer
4. Use Branch Protection
Protect critical branches:
- Settings → Branches
- Add protection rule for
main
- Require pull request reviews
- Require status checks to pass
- 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
Recommended Git Flow
Step-by-Step Process
Create feature branch
git checkout -b feature/add-new-taxonomy
Make changes
# Add or modify resources
vim kodexa-metadata/data-definitions/new-taxonomy.yaml
# Update manifest if needed
vim manifests/main.yaml
Test locally
# Set environment variables
export KODEXA_DEV_API_KEY="your-dev-key"
# Preview changes
kdx sync deploy --dry-run
Commit and push
git add .
git commit -m "feat: add new document taxonomy"
git push origin feature/add-new-taxonomy
Open pull request
- GitHub automatically runs dry-run validation
- Review deployment preview in PR comments
- Request team review
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:
- Settings → Secrets and variables → Actions
- Confirm secret name matches exactly
- Check environment restrictions if using GitHub environments
Authentication Failed
Issue: “Authentication failed” or “Invalid API key”
Solutions:
- Verify secret value - Regenerate API key if needed
- Check key permissions - Ensure key has deployment access
- 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