Version Control with Git​Version ​Control with ​Git

Learn how to pair Kestra with Git so you can version flows, namespace files, and related artifacts alongside your application code.


Kestra supports version control with Git. You can use one or more repositories to store your flows, namespace files, apps, tests, and dashboards, tracking changes through Git history.

There are multiple ways to combine Kestra with Git:

  • SyncFlows implements GitOps with Git as the single source of truth for flows.
  • SyncNamespaceFiles syncs namespace files the same way.
  • PushFlows commits and pushes flow edits from the UI to Git, useful when you rely on the built-in editor but still want version history.
  • PushNamespaceFiles does the same for namespace files.
  • Clone clones a repository directly into a flow so scripts are available at runtime.
  • TenantSync synchronizes all namespaces in a tenant, including flows, files, apps, tests, and dashboards.
  • NamespaceSync keeps a single namespace in sync with a Git repo.
  • A custom CI/CD pipeline lets you manage deployments yourself (GitHub Actions, Terraform, etc.) while keeping Git authoritative.

The image below shows how to choose the right pattern based on your needs:

git

Let's dive into each of these patterns and when to use them.

Git SyncFlows and SyncNamespaceFiles

The Git SyncFlows pattern implements GitOps with Git as the single source of truth. Store flows in Git, and run a system flow that automatically syncs changes into Kestra. The Git SyncNamespaceFiles pattern mirrors this for namespace files.

Here's how it works:

  • Store flows and namespace files in Git.
  • Schedule a system flow that syncs changes from Git to Kestra.
  • Modify files in Git whenever you need to change a flow or namespace file.
  • The system flow syncs those changes, overwriting any conflicting UI edits with the Git version.

This pattern suits teams that treat Git as the single source of truth and prefer not to edit flows or namespace files in the UI. No CI/CD pipeline is required, so it's ideal if you already follow GitOps practices or come from a Kubernetes background.

Here is an example system flow that you can use to declaratively sync changes from Git to Kestra:

yaml
id: sync_from_git
namespace: system

tasks:
  - id: git
    type: io.kestra.plugin.git.SyncFlows
    url: https://github.com/kestra/scripts
    branch: main
    username: git_username
    password: "{{ secret('GITHUB_ACCESS_TOKEN') }}"
    targetNamespace: git
    includeChildNamespaces: true # optional; by default, it's set to false to allow explicit definition
    gitDirectory: your_git_dir

triggers:
  - id: schedule
    type: io.kestra.plugin.core.trigger.Schedule
    cron: "*/1 * * * *" # every minute

Commit this flow to Git or add it via the built-in editor; it won't be overwritten by reconciliation.

You can also sync namespace files with the example below:

yaml
id: sync_from_git
namespace: system


tasks:
  - id: git
    type: io.kestra.plugin.git.SyncNamespaceFiles
    namespace: prod
    gitDirectory: _files # optional; set to _files by default
    url: https://github.com/kestra-io/flows
    branch: main
    username: git_username
    password: "{{ secret('GITHUB_ACCESS_TOKEN') }}"

You can also trigger this flow with a GitHub webhook whenever changes land in Git:

yaml
id: sync_from_git
namespace: system

tasks:
  - id: git
    type: io.kestra.plugin.git.SyncFlows
    url: https://github.com/kestra/scripts
    branch: main
    targetNamespace: git
    username: git_username
    password: "{{ secret('GITHUB_ACCESS_TOKEN') }}"

triggers:
  - id: github_webhook
    type: io.kestra.plugin.core.trigger.Webhook
    key: "{{ secret('WEBHOOK_KEY') }}"

The webhook key authenticates requests and prevents unauthorized access. For the flow above, paste the following URL into your repository’s Webhooks settings:

bash
http://your_kestra_host:8080/api/v1/<your_tenant>/executions/webhook/prod/sync_from_git/your_secret_key

github_webhook

Following the pattern:

bash
http://<host>/api/v1/<tenant>/executions/webhook/<namespace>/<flow>/<webhook_key>

CI/CD

The CI/CD pattern still treats Git as the single source of truth but pushes code changes to Kestra whenever a pull request merges. Unlike the Sync pattern, you manage the automation (GitHub Actions, Terraform, etc.). See the CI/CD docs for setup details.

Git PushFlows and PushNamespaceFiles

The Git PushFlows pattern lets you edit flows in the UI while pushing versions to Git. The Git PushNamespaceFiles pattern offers the same workflow for namespace files.

Example flow for pushing from Kestra to Git:

yaml
id: push_to_git
namespace: system

tasks:
  - id: commit_and_push
    type: io.kestra.plugin.git.PushFlows
    url: https://github.com/kestra-io/scripts
    sourceNamespace: dev
    targetNamespace: pod
    flows: "*"
    branch: kestra
    username: github_username
    password: "{{ secret('GITHUB_ACCESS_TOKEN') }}"
    commitMessage: add namespace files changes

triggers:
  - id: schedule
    type: io.kestra.plugin.core.trigger.Schedule
    cron: "* */1 * * *" # every hour

Example flow for pushing namespace files:

yaml
id: push_to_git
namespace: system

tasks:
  - id: commit_and_push
    type: io.kestra.plugin.git.PushNamespaceFiles
    namespace: dev
    files: "*"
    gitDirectory: _files
    url: https://github.com/kestra-io/scripts # required string
    username: git_username
    password: "{{ secret('GITHUB_ACCESS_TOKEN') }}"
    branch: dev
    commitMessage: "add namespace files"


triggers:
  - id: schedule_push_to_git
    type: io.kestra.plugin.core.trigger.Schedule
    cron: "*/15 * * * *"

Use this pattern to push to a feature branch and open a pull request for review.

Git Clone

The Git Clone pattern clones a repository at runtime so you can orchestrate code managed elsewhere, for example:

Git TenantSync and NamespaceSync

Both Git TenantSync and Git NamespaceSync give you full control over synchronizing Kestra objects with your Git repository.

  • TenantSync – synchronizes all namespaces in a tenant, including flows, files, apps, tests, and dashboards.
    • Requires kestraUrl and auth so the task can validate tenant-wide RBAC.
    • Useful when you need to back up the entire tenant to Git and promote environments through pull requests.
  • NamespaceSync – synchronizes objects within a single namespace with your Git repository.
    • Requires the namespace property but not kestraUrl or auth; it relies on namespace-level RBAC and can be run by any user with sufficient permissions.
    • Ideal for teams that sync one namespace per repository, allowing owners to manage their own syncs.

Both plugins support:

  • sourceOfTruth (GIT or KESTRA) to define the update strategy.
  • whenMissingInSource with options DELETE, KEEP, or FAIL to control how missing objects should be handled.
  • An opinionated folder structure for flows, apps, dashboards, tests, and files with one folder per namespace.
  • protectedNamespaces to ensure your Kestra objects from critical namespaces (such as system) are not accidentally deleted when sourceOfTruth is GIT.
  • Validation rules requiring explicit Git branch and optional gitDirectory.
  • Options like dryRun and onInvalidSyntax for safe rollouts and error handling.

Example usage of the TenantSync task:

yaml
id: tenant_git_sync
namespace: system

tasks:
  - id: tenant
    type: io.kestra.plugin.git.TenantSync
    sourceOfTruth: KESTRA
    whenMissingInSource: DELETE
    url: https://github.com/org/repo
    branch: main
    protectedNamespaces:
      - system
    kestraUrl: http://localhost:8080
    auth:
      username: [email protected]
      password: "{{ secret('KESTRA_PASSWORD') }}"

Example usage of the NamespaceSync task:

yaml
id: namespace_git_sync
namespace: system

tasks:
  - id: namespace
    type: io.kestra.plugin.git.NamespaceSync
    namespace: company.team
    sourceOfTruth: GIT
    whenMissingInSource: KEEP
    url: https://github.com/org/repo
    branch: main
    protectedNamespaces:
      - system

Was this page helpful?