Backup n8n Workflows to Gitea (Automated Guide)
Imagine losing your favorite automation…
You just spent an afternoon crafting the perfect n8n workflow. It talks to 5 tools, cleans your data, sends the right emails, and basically runs your life so you do not have to. Then something breaks, a workflow gets corrupted, or you accidentally hit delete before coffee. Now you are clicking around trying to remember what you did three versions ago.
That is the moment you realize: “Huh, maybe I should have backed this up somewhere.” Preferably somewhere versioned, safe, and not inside a single database that could vanish with one bad day.
This is exactly what this n8n workflow template solves. It automatically backs up all your n8n workflows as JSON files into a Gitea repository on a schedule you control. No more manual exports, no more “which version was that”, and no more hoping nothing breaks.
What this n8n to Gitea backup workflow actually does
This template is an automated backup system for your n8n workflows using Gitea as the storage backend. In plain language, it:
- Runs on a schedule you define, for example every 45 minutes or once a day
- Pulls all workflows from your n8n instance via the n8n API
- Turns each workflow into a pretty-printed JSON file
- Stores each file in a Gitea repository as
<workflow-name>.json - Creates new files when workflows are new, and updates files only when something has changed
Behind the scenes it talks to the Gitea API, handles base64 encoding for file contents, checks if the file already exists, and updates it using the proper SHA when needed. You get version history, readable diffs, and peace of mind, without lifting a finger after setup.
Why bother backing up n8n workflows to Gitea?
If you are already using n8n, you probably like automation and dislike repetitive tasks. Manual exports definitely fall into the “repetitive and annoying” category. This workflow fixes that and gives you:
- Fast recovery if a workflow is lost, corrupted, or accidentally edited into oblivion
- Clear version history so you can see what changed and roll back if needed
- Self-hosted safety by storing everything in your own Gitea instance instead of a public cloud Git provider
- Flexible backup frequency that you can match to how often your workflows change
In short, you get Git-style safety for your automations without adding another manual task to your to-do list.
What you need before you start
Before importing and running the template, make sure you have:
- An n8n instance with API access that can list workflows
- A Gitea repository where the backup JSON files will live
- A Gitea personal access token with repository read/write permissions
- n8n credentials configured for:
- your n8n API
- your Gitea token (used by HTTP Request nodes)
Quick setup: from zero to automatic backups
Here is the short version of getting the template running. After this section you will find a more detailed node-by-node breakdown if you like to know exactly what is happening.
Step 1 – Configure global repository variables
Open the Globals node in the workflow and set these values:
- repo.url: your Gitea base URL, for example
https://git.example.com - repo.owner: the repository owner, user or organization
- repo.name: the repository name, for example
workflows
These globals keep the workflow reusable and easy to move between environments without editing every node.
Step 2 – Create a Gitea personal access token
In your Gitea instance:
- Go to Settings → Applications
- Click Generate New Token
- Give it repo read/write permissions
In n8n, create an HTTP credential that uses this token. Use the header:
Authorization: Bearer YOUR_PERSONAL_ACCESS_TOKEN
Do not forget the space after Bearer. That tiny space is the difference between “works perfectly” and “401 Unauthorized”.
Step 3 – Assign credentials to the right nodes
In the n8n workflow:
- Assign your Gitea token credential to the HTTP Request nodes that talk to Gitea:
GetGiteaPutGiteaPostGitea
- Assign your n8n API credential to the node that lists workflows from your n8n instance
Step 4 – Pick your backup schedule
Open the Schedule Trigger node and set how often you want backups to run:
- Every 45 minutes, like the example
- Hourly
- Daily
- Whatever matches how often you change workflows
More changes, more frequent backups. Less change, fewer runs. Your future self will thank you either way.
Under the hood: how the workflow logic works
Now let us walk through the main nodes so you know exactly what this template is doing for you.
Schedule Trigger
This node is the starting point. It fires the workflow at the interval you configured. The example uses a 45 minute interval, but you can easily switch it to hourly, daily, or any other supported schedule.
Globals node
The Globals node acts as a mini settings file inside your workflow. It stores values like:
repo.urlrepo.ownerrepo.name
By centralizing these values, you can move between test, staging, and production Gitea instances with minimal edits.
n8n API node – fetching workflows
The n8n (API node) connects to your own n8n instance and retrieves all available workflows. Make sure the credential used here has permission to list workflows via the n8n API.
ForEach / Split in Batches – handling workflows one by one
Once all workflows are fetched, the workflow uses a combination of ForEach or SplitInBatches logic to process each workflow individually. This way:
- Each workflow becomes its own JSON file in Gitea
- Large numbers of workflows are processed in manageable chunks
- You avoid hammering the Gitea API all at once
GetGitea (HTTP Request) – does the file already exist?
The GetGitea HTTP Request node checks if a file for the current workflow already exists in the repo. It calls Gitea’s contents endpoint like this:
GET /api/v1/repos/{owner}/{repo}/contents/{path}.json
The {path} usually corresponds to the workflow name, with URL encoding applied so special characters do not break the request.
If the file is missing, Gitea returns a 404. The node is configured to continue on error so the workflow can handle this case gracefully and move on to file creation.
Exist (If node) – branching for create vs update
The Exist If node examines the result from GetGitea and decides what to do next:
- If GetGitea returned a 404, the file does not exist, so the flow goes down the create file path
- If it returned an existing file payload, the flow goes down the update file path
Base64 encoding nodes (Create & Update)
Gitea expects file contents to be sent as base64 encoded strings. To keep your repo readable and your diffs clean, the workflow uses a small Python code node to:
- Extract the workflow JSON object
- Pretty-print it with indentation so the JSON in Gitea looks nice
- Encode the resulting JSON string as base64
The core idea looks like this:
json_string = json.dumps(workflow_object, indent=4)
base64_string = base64.b64encode(json_string.encode('utf-8')).decode('utf-8')
Both the create and update paths use this encoded content when talking to the Gitea API.
Changed (If node) – only update when needed
To avoid noisy commits, the Changed If node compares the newly generated base64 content with the existing content from Gitea:
- If the content is the same, no update is sent
- If the content differs, the workflow calls PutGitea to update the file
This keeps your commit history clean and meaningful, instead of “updated the same thing again” every 45 minutes.
PutGitea and PostGitea (HTTP Request) – saving files
Two HTTP Request nodes handle writing to Gitea:
- PostGitea (create): sends a
POSTto the contents endpoint to create a new file with the base64 encoded content - PutGitea (update): sends a
PUTrequest including the file’sshafrom GetGitea to update the existing file content
Gitea API request example
Gitea’s contents API accepts several useful JSON fields in the request body, including:
content– base64 encoded file contents (required)message– commit messagebranch– branch name to commit tosha– required for updates to existing files
Here is an example cURL call to update a file:
curl -X PUT "https://git.example.com/api/v1/repos/owner/repo/contents/workflow.json" \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "content":"BASE64_CONTENT", "message":"Backup: update workflow.json", "sha":"FILE_SHA" }'
The provided n8n template sends the minimal required fields by default. You can optionally add message and branch in the HTTP body parameters for more descriptive commits and custom branches.
Testing the template before you trust it
Before you rely on this workflow as your safety net, give it a quick test run.
- Run the workflow manually in n8n and confirm:
- Workflows are fetched correctly from your n8n instance
- JSON files appear in the Gitea repository
- Open the files in Gitea and check that:
- The JSON is pretty printed and readable
- Commits look sensible in the history
- Enable the Schedule Trigger once you are happy with the results so backups run automatically
Security tips and best practices
Automation is great, leaking tokens is not. A few sensible precautions:
- Store your Gitea token in n8n credentials, do not hardcode it in nodes
- Use a least-privilege token scoped only to the repositories you need, with read/write permissions
- Limit repository access in Gitea and rotate tokens regularly
- If n8n is running in production, also back up the n8n database and credential store using appropriate secure methods
Troubleshooting: when your backup needs a backup
Common errors and how to fix them
- 401 Unauthorized
Check the Authorization header format in your n8n credentials. Some setups expect:Authorization: token TOKENorAuthorization: Bearer TOKEN
Make sure the correct credential is attached to all Gitea HTTP Request nodes.
- 404 Not Found
Verify:- The
repo.ownerandrepo.namevalues - The file path and workflow name mapping
The template uses URL encoding for names so paths with special characters still work.
- The
- Encoding errors
Confirm that:- The JSON is valid before encoding
- The base64 encoding step is applied correctly
Pretty-printing the JSON helps you spot structural issues and makes diffs easier to read.
- Rate limiting or performance problems
If you have a lot of workflows, the SplitInBatches logic already helps. You can:- Adjust batch size
- Increase the interval between runs
- Add custom rate limiting if your Gitea instance is strict
Customization ideas to make it your own
Once the basic backup is working, you can start adding quality-of-life improvements.
- Smarter commit messages
Include timestamps, workflow IDs, or change hints in the commit message for easier tracking in Gitea. - Branch strategies
Instead of committing to the default branch, create a branch per day or week and push backups there. - Handling sensitive data
If workflows contain secrets, either:- Strip them out before committing, recommended
- Or encrypt sensitive fields before sending them to Gitea
- Use other Git providers
Prefer GitHub or GitLab? You can adapt the same logic by:- Swapping Gitea API endpoints for the provider’s API
- Updating credentials accordingly
Wrapping up: let automation back up your automation
Backing up your n8n workflows to a Gitea repository gives you versioned, auditable, and easily recoverable automation definitions with almost no ongoing effort. Once this template is in place, it quietly keeps everything safe while you focus on building new workflows instead of babysitting old ones.
Next steps:
- Import the n8n workflow template
- Add your Gitea token and n8n API credentials
- Run a manual test and confirm files appear correctly in Gitea
