New to Kestra?
Use blueprints to kickstart your first workflows.
Use Kestra to sync namespaces, flows, files, and dashboards from Git into your tenant every 15 minutes with a unidirectional GitOps pipeline.
id: tenant-sync-from-git
namespace: system
tasks:
- id: tenant_sync
type: io.kestra.plugin.git.TenantSync
sourceOfTruth: GIT
whenMissingInSource: DELETE
protectedNamespaces:
- system
url: https://github.com/example_org/example_repo
username: "{{ secret('GITHUB_USERNAME') }}"
password: "{{ secret('GITHUB_ACCESS_TOKEN') }}"
branch: main
gitDirectory: example_directory
kestraUrl: "http://localhost:8080"
auth:
username: "{{ secret('KESTRA_USERNAME') }}"
password: "{{ secret('KESTRA_PASSWORD') }}"
triggers:
- id: every_15_minutes
type: io.kestra.plugin.core.trigger.Schedule
cron: "*/15 * * * *"
This blueprint turns your Git repository into the single source of truth for an entire Kestra tenant. Every 15 minutes, the flow pulls the latest namespaces, flows, KV pairs, files, and dashboards from a branch in GitHub (or any Git provider) and reconciles them with the running Kestra instance. Resources that exist in Git are created or updated, resources that disappear from Git are deleted from Kestra, and a configurable list of protected namespaces is left untouched. This gives platform teams a clean, auditable GitOps workflow for managing orchestration assets across environments.
A io.kestra.plugin.core.trigger.Schedule trigger named every_15_minutes fires the flow on the cron expression */15 * * * *. On each run, the tenant_sync task of type io.kestra.plugin.git.TenantSync connects to the configured Git url and branch, reads the contents of gitDirectory, and applies them to the Kestra tenant reachable at kestraUrl. The task uses sourceOfTruth: GIT and whenMissingInSource: DELETE, so the Git tree always wins and anything missing in source is removed from Kestra. The protectedNamespaces list (here, system) is excluded from deletion so that platform flows like this one are never wiped out by their own sync.
protectedNamespaces.Git providers do not run reconciliation loops, and most ad hoc cron jobs lack visibility, retries, and secret management. Kestra fills that gap. The Schedule trigger gives you predictable execution, every run is recorded with full lineage and logs, failures can be retried declaratively, and credentials are pulled from the secret manager via {{ secret('NAME') }} instead of being baked into scripts. Because the flow is plain YAML, you can version it in the same repo it syncs, review changes through pull requests, and promote them through environments without bespoke tooling.
The flow reads the following secrets via {{ secret('...') }}:
GITHUB_USERNAME: Git username used to clone the repository.GITHUB_ACCESS_TOKEN: personal access token or password for Git.KESTRA_USERNAME: Kestra API username used by TenantSync.KESTRA_PASSWORD: Kestra API password used by TenantSync.GITHUB_USERNAME, GITHUB_ACCESS_TOKEN, KESTRA_USERNAME, and KESTRA_PASSWORD to your secret manager.url, branch, and gitDirectory properties on the tenant_sync task to point at your repository layout.kestraUrl to the address of the target Kestra instance (for example, http://localhost:8080 for local testing).protectedNamespaces to cover any namespaces you never want overwritten or deleted.system) and let the every_15_minutes schedule take over.cron expression on the every_15_minutes trigger.whenMissingInSource to KEEP if you want additive syncs that never delete.protectedNamespaces to carve out areas owned outside of Git.kestraUrl and auth and running the flow per environment.