How to Automatically Backup Kestra to GitLab (Step-by-Step Guide)

Why You Should Always Backup Kestra

If you're running production workflows in Kestra, backups are not optional — they are critical.

Your Kestra instance likely contains:

  • Production automation flows
  • Recon pipelines
  • Infrastructure scripts
  • Scheduled jobs
  • Business-critical workflow logic

A single disk failure, database corruption, or accidental deletion can wipe out months of work.

Even worse?
Workflow definitions often change frequently — meaning manual exports are unreliable.

The safest approach is:

✅ Automated
✅ Version controlled
✅ Scheduled
✅ Off-server storage

And that’s exactly what we’re going to build. Well, mostly. My Gitlab instance is actually on my local network, but that can be easily sorted by a remote backup of the entire lab server. 3 copies, 2 media types, 1 remote - Remember for backups, 2 is 1, 1 is none.


Backup Strategy Overview

We’ll use:

  • Native Kestra Git plugins
  • A scheduled cron trigger
  • Git-based version control
  • Secure token authentication
  • Concurrency protection

The backups will:

  • Run every day at 20:00
  • Push flows to Git
  • Push namespace scripts
  • Fail safely if a run is already in progress

We’ll store everything inside GitLab, but this works with any Git-compatible server.


Production-Ready Kestra Backup Flow

Below is the automation flow:

id: git_push
namespace: system
tasks:
  - id: push
    type: io.kestra.plugin.core.flow.ForEach
    tasks:
      - id: flows
        type: io.kestra.plugin.git.PushFlows
        sourceNamespace: "{{ taskrun.value }}"
        gitDirectory: "{{'flows/' ~ taskrun.value}}"
        includeChildNamespaces: false
      - id: scripts
        type: io.kestra.plugin.git.PushNamespaceFiles
        namespace: "{{ taskrun.value }}"
        gitDirectory: "{{'scripts/' ~ taskrun.value}}"
    values:
      - ansible
      - outputs
      - posting
      - proxmox

triggers:
  - id: schedule_push_to_git
    type: io.kestra.plugin.core.trigger.Schedule
    cron: 0 20 * * *
pluginDefaults:
  - type: io.kestra.plugin.git
    values:
      username: "{{ secret('GITLAB_USERNAME') }}"
      url: https://gitlab-01.local/<your user>/kestra
      password: "{{ secret('GITLAB_ACCESS_TOKEN') }}"
      branch: main
      dryRun: false
concurrency:
  limit: 1
  behavior: FAIL

How This Backup Works

1️⃣ ForEach Namespace Loop

The ForEach task iterates through multiple namespaces:

  • ansible
  • proxmox
  • outputs
  • etc

Each namespace gets backed up separately.

This keeps your Git repo structured:

flows/ansible/
flows/outputs/
scripts/ansible/
scripts/outputs/

Clean. Organized. Restorable.


2️⃣ PushFlows

This task:

  • Extracts all flows
  • Converts them to YAML
  • Commits them to Git
  • Pushes to the main branch

Every backup creates version history.

That means:

  • You can diff changes
  • You can revert flows
  • You can audit modifications

3️⃣ PushNamespaceFiles

This backs up namespace-level files such as:

  • Python scripts
  • Shell scripts
  • Templates
  • Assets

This is critical because scripts often change independently of flows.


4️⃣ Scheduled Trigger

cron: 0 20 * * *

Runs daily at 20:00.

Why daily?

Because:

  • Most teams modify flows daily
  • It minimizes data loss
  • It keeps Git history clean

You can adjust to hourly if needed.


5️⃣ Secure Secret Handling

Never hardcode credentials.

This flow uses:

username: "{{ secret('GITLAB_USERNAME') }}"
password: "{{ secret('GITLAB_ACCESS_TOKEN') }}"

Store these securely inside Kestra’s secret store.


Why Git Is the Best Backup Target

Backing up to Git gives you:

  • Version history
  • Distributed storage
  • Easy replication
  • CI/CD integration
  • Offsite protection

If your Kestra server dies, you simply:

  1. Reinstall Kestra
  2. Clone repo
  3. Re-import flows

Done.


Recommended Backup Hardware

If you're running Kestra on-prem, consider adding:

Clicking on these links and purchasing the items doesn't cost you any more, but does help me keep this blog free.


Extra Hardening Tips

🔒 1. Enable Git commit signing

🔁 2. Mirror repo to secondary Git server

🗂 3. Enable GitLab repo backups

📦 4. Snapshot the Kestra database

🧪 5. Test restore quarterly

Backups are useless if you never test them.


Concurrency Protection Explained

concurrency:
  limit: 1
  behavior: FAIL

This prevents overlapping backup runs.

Why important?

If a backup takes longer than expected, the next scheduled job will fail instead of corrupting the repo.

Safe > Fast.


Common Mistakes to Avoid

❌ Hardcoding credentials
❌ Running backups on the same disk
❌ Not version controlling flows
❌ Forgetting namespace scripts
❌ Not testing restore


Final Thoughts

If you rely on Kestra for production workloads, automated Git backups are mandatory — not optional.

This approach gives you:

  • Full automation
  • Version tracking
  • Offsite protection
  • Minimal maintenance
  • Enterprise-grade resilience

Set it up once. Sleep better forever. Just remember to backup your gitlab server as well.


About the author

Tim Wilkes is a UK-based security architect with over 15 years of experience in electronics, Linux, and Unix systems administration. Since 2021, he's been designing secure systems for a telecom company while indulging his passions for programming, automation, and 3D printing. Tim shares his projects, tinkering adventures, and tech insights here - partly as a personal log, and partly in the hopes that others will find them useful.

Want to connect or follow along?

LinkedIn: [phpsytems]
Twitter / X: [@timmehwimmy]
Mastodon: [@timmehwimmy@infosec.exchange]


If you've found a post helpful, consider supporting the blog - it's a part-time passion that your support helps keep alive.

⚠️ Disclaimer

This post may contain affiliate links. If you choose to purchase through them, I may earn a small commission at no extra cost to you. I only recommend items and services I’ve personally read or used and found valuable.

As an Amazon Associate I earn from qualifying purchases.