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: FAILHow 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:
- Reinstall Kestra
- Clone repo
- Re-import flows
Done.
Recommended Backup Hardware
If you're running Kestra on-prem, consider adding:
- External SSD for snapshot backups such as the Samsung T7 Portable SSD
- NAS for redundant storage - Synology NAS
- UPS battery backup - APC UPS
- Dedicated Git server hardware
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: FAILThis 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.