n8n Git Automation: Version Control, Backup, and CI/CD for Your Workflows
Your workflow just vanished. And there’s no way to get it back.
Someone on your team accidentally overwrote it. Or maybe a failed update corrupted the database. Perhaps you made changes that broke everything, and now you can’t remember what it looked like before. Whatever the cause, hours of careful automation work are gone.
This happens more often than you’d think. The n8n community forums are filled with stories of lost workflows, accidental deletions, and update disasters. And the recovery options without version control are brutal: rebuild from scratch, restore from an old database backup (if you have one), or accept the loss.
The Hidden Risk
Most n8n users operate without a safety net. They build increasingly complex automations, trusting that the workflows will always be there. But n8n workflows live in a database, and databases can fail. Updates can break things. Team members can overwrite each other’s work.
Common disaster scenarios include:
- Accidental deletion or overwrite by team members
- Database corruption during n8n updates
- Server failures without recent backups
- Changes that break production with no way to revert
- Lost work when migrating between instances
What Version Control Solves
Git transforms how you manage n8n workflows. Instead of hoping nothing goes wrong, you get complete history of every change ever made. Revert to any previous version instantly. Compare what changed between versions. Collaborate with confidence knowing you can’t accidentally destroy someone else’s work.
Version control also enables professional deployment practices. Push changes through development, staging, and production environments. Review changes before they go live. Automate deployments when code merges. These patterns separate hobby projects from production-ready automation infrastructure.
What You’ll Learn
- How n8n’s native source control works (and its limitations)
- Using GitHub and GitLab nodes to automate workflow backups
- Building automated backup workflows that run daily
- Setting up bidirectional sync between n8n and Git
- Integrating with CI/CD pipelines for automated deployments
- Managing multiple environments (dev/staging/prod)
- Troubleshooting common Git integration issues
Why Git for n8n Workflows
n8n workflows are code. They’re stored as JSON, they control business logic, and they can break just like any other code. Treating them as code means applying the same practices that keep software projects reliable: version control, code review, and controlled deployments.
The Case for Workflow Version Control
Track every change. Git records who changed what, when, and why. When something breaks, you can see exactly which modification caused the problem. When auditors ask about your automation processes, you have a complete history.
Revert mistakes instantly. Made a change that broke production? Roll back to the previous version in seconds. No frantic attempts to remember what it looked like before. No rebuilding from memory.
Collaborate safely. Multiple people can work on different workflows without overwriting each other. Branches let you develop new features without affecting production. Merge conflicts are surfaced and resolved, not silently overwritten.
Disaster recovery. If your n8n server dies, your workflows survive. Clone the repository to a new instance, import the workflows, and you’re back in business.
When You Need Git Automation
| Scenario | Git Automation Priority |
|---|---|
| Solo developer, testing | Nice to have |
| Solo developer, production workflows | Recommended |
| Small team, shared instance | Essential |
| Multiple environments (dev/staging/prod) | Required |
| Compliance requirements | Required |
| Business-critical automation | Required |
If your workflows handle anything important, or if more than one person touches them, version control isn’t optional. The question isn’t whether you’ll need to recover from a disaster, but when.
Manual Export vs. Automated Git Backup
| Aspect | Manual Export | Automated Git Backup |
|---|---|---|
| Frequency | When you remember | Every change or scheduled |
| Human error | High (easy to forget) | Low (runs automatically) |
| Version history | Multiple files, hard to track | Complete Git history |
| Recovery time | Find file, import manually | Git checkout, done |
| Collaboration | Share files, hope for the best | Proper branching and merging |
| Effort | Manual work every time | Set up once, runs forever |
Manual exports are better than nothing. But automated Git backup is what separates professional operations from hoping for the best.
n8n’s Native Source Control
n8n includes built-in source control for environment management. Understanding what it does and doesn’t do helps you decide when to use it versus building custom solutions.
How It Works
Native source control uses a push-pull pattern. You work on workflows in your n8n instance, then push them to a connected Git repository. To get changes from Git, you pull them into n8n.
When you push, n8n saves:
- Workflow JSON definitions
- Workflow tags
- Credential stubs (references, not actual secrets)
- Variable stubs
When you pull, n8n overwrites local workflows with whatever is in Git. This is a one-way operation - local changes are replaced, not merged.
Branch-Based Environments
The real power of native source control is environment management. Connect different n8n instances to different Git branches:
- Development instance connects to
developbranch - Staging instance connects to
stagingbranch - Production instance connects to
mainbranch
Push changes from development, merge them through your Git workflow, and pull them into production. This creates a proper deployment pipeline without custom tooling.
Setup Requirements
To use native source control, you need:
- n8n Enterprise (not available in Community Edition)
- A Git repository (GitHub, GitLab, Bitbucket, or self-hosted)
- Either SSH access (deploy keys) or HTTPS access (Personal Access Tokens)
Configuration happens in n8n’s settings under Source Control. You provide the repository URL, authentication credentials, and branch name.
Limitations to Understand
Native source control is not full version control. Key limitations:
- No pull request workflow inside n8n. You can use PRs in your Git provider, but n8n doesn’t show diffs or handle reviews.
- Pull overwrites everything. There’s no merge - pulling replaces local workflows entirely.
- Enterprise only. Community Edition users need custom solutions.
- Basic operations only. No cherry-picking, no reverting individual files, no complex Git operations.
For many teams, these limitations are acceptable. The built-in feature handles the common case well. For more control, you’ll need custom automation.
GitHub and GitLab Nodes for Git Automation
n8n includes dedicated nodes for Git operations. These let you build custom backup, sync, and deployment workflows that go beyond native source control.
GitHub Node Operations
The GitHub node supports file and repository operations:
File Operations:
- Create File - Add a new file with commit message
- Edit File - Update existing file content
- Get File - Read file content from repository
- Delete File - Remove file with commit message
Repository Operations:
- Get Issues - List or fetch issues
- Create Issue - Create new issues
- Get Repositories - List user repositories
For workflow backup, you’ll primarily use Create File, Edit File, and Get File.
GitLab Node Operations
The GitLab node provides similar capabilities:
- Create File - Add file to repository
- Edit File - Modify existing file
- Get File - Read file content
- Delete File - Remove file
The patterns for GitLab automation mirror GitHub workflows with minor API differences.
Git Node for Local Repositories
The Git node handles local repository operations on the server where n8n runs:
- Clone - Clone a repository to local filesystem
- Add - Stage files for commit
- Commit - Create a commit with message
- Push - Push commits to remote
- Pull - Pull changes from remote
- Fetch - Fetch without merging
- Status - Check repository status
This approach requires Git installed on the n8n server and works well for self-hosted instances where you control the environment.
Choosing Your Approach
| Approach | Best For | Requirements |
|---|---|---|
| GitHub/GitLab nodes | Cloud n8n, simple backups | API credentials |
| Git node (local) | Self-hosted, complex operations | Git on server |
| Execute Command | Maximum control | Git + shell access |
| Native source control | Enterprise, environments | Enterprise license |
For most backup scenarios, the GitHub or GitLab nodes are simplest. They work with n8n Cloud and don’t require server-level access.
Automated Workflow Backup to GitHub
Let’s build a complete backup workflow that automatically saves all your n8n workflows to GitHub. This workflow runs on a schedule and handles both new workflows and updates to existing ones.
Workflow Architecture
- Schedule Trigger - Runs daily at 2 AM
- n8n Node - Exports all workflows via API
- Loop Over Items - Process each workflow
- GitHub Node (Get) - Check if file exists
- IF Node - Route to create or update
- GitHub Node (Create/Edit) - Save with commit
- Error Handling - Catch and notify on failures
Prerequisites
Before building this workflow, you need:
- GitHub Personal Access Token with
reposcope - n8n API key (for accessing your own workflows)
- A GitHub repository for storing backups
Create these credentials in n8n before proceeding. For credential security best practices, see our credential management guide.
Complete Workflow JSON
Here’s a production-ready backup workflow you can import directly:
{
"name": "Backup All Workflows to GitHub",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "hours",
"hoursInterval": 24
}
]
}
},
"name": "Daily Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [250, 300],
"typeVersion": 1.1
},
{
"parameters": {
"resource": "workflow",
"operation": "getAll",
"returnAll": true
},
"name": "Get All Workflows",
"type": "n8n-nodes-base.n8n",
"position": [450, 300],
"typeVersion": 1
},
{
"parameters": {
"options": {}
},
"name": "Loop Over Workflows",
"type": "n8n-nodes-base.splitInBatches",
"position": [650, 300],
"typeVersion": 3
},
{
"parameters": {
"owner": "your-github-username",
"repository": "n8n-workflow-backups",
"filePath": "={{ 'workflows/' + $json.name.replace(/[^a-zA-Z0-9-_]/g, '_') + '.json' }}"
},
"name": "Check File Exists",
"type": "n8n-nodes-base.github",
"position": [850, 300],
"typeVersion": 1,
"credentials": {
"githubApi": {
"id": "1",
"name": "GitHub"
}
},
"onError": "continueRegularOutput"
},
{
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{ $json.sha !== undefined }}",
"value2": true
}
]
}
},
"name": "File Exists?",
"type": "n8n-nodes-base.if",
"position": [1050, 300],
"typeVersion": 1
},
{
"parameters": {
"operation": "edit",
"owner": "your-github-username",
"repository": "n8n-workflow-backups",
"filePath": "={{ 'workflows/' + $('Loop Over Workflows').item.json.name.replace(/[^a-zA-Z0-9-_]/g, '_') + '.json' }}",
"fileContent": "={{ JSON.stringify($('Loop Over Workflows').item.json, null, 2) }}",
"commitMessage": "={{ 'Update: ' + $('Loop Over Workflows').item.json.name }}",
"additionalParameters": {
"sha": "={{ $json.sha }}"
}
},
"name": "Update Existing",
"type": "n8n-nodes-base.github",
"position": [1250, 200],
"typeVersion": 1
},
{
"parameters": {
"operation": "create",
"owner": "your-github-username",
"repository": "n8n-workflow-backups",
"filePath": "={{ 'workflows/' + $('Loop Over Workflows').item.json.name.replace(/[^a-zA-Z0-9-_]/g, '_') + '.json' }}",
"fileContent": "={{ JSON.stringify($('Loop Over Workflows').item.json, null, 2) }}",
"commitMessage": "={{ 'Add: ' + $('Loop Over Workflows').item.json.name }}"
},
"name": "Create New",
"type": "n8n-nodes-base.github",
"position": [1250, 400],
"typeVersion": 1
}
],
"connections": {
"Daily Trigger": {
"main": [[{"node": "Get All Workflows", "type": "main", "index": 0}]]
},
"Get All Workflows": {
"main": [[{"node": "Loop Over Workflows", "type": "main", "index": 0}]]
},
"Loop Over Workflows": {
"main": [[{"node": "Check File Exists", "type": "main", "index": 0}]]
},
"Check File Exists": {
"main": [[{"node": "File Exists?", "type": "main", "index": 0}]]
},
"File Exists?": {
"main": [
[{"node": "Update Existing", "type": "main", "index": 0}],
[{"node": "Create New", "type": "main", "index": 0}]
]
},
"Update Existing": {
"main": [[{"node": "Loop Over Workflows", "type": "main", "index": 0}]]
},
"Create New": {
"main": [[{"node": "Loop Over Workflows", "type": "main", "index": 0}]]
}
}
}
Customization Notes
Change the repository owner and name. Replace your-github-username and n8n-workflow-backups with your actual values.
Adjust the schedule. The workflow runs every 24 hours. For busier environments, consider running more frequently or triggering on workflow saves via webhook.
Add error notifications. Connect an Error Trigger workflow to get Slack, email, or other notifications when backups fail. See our workflow testing guide for error handling patterns.
Exclude specific workflows. Add a Filter node after “Get All Workflows” to skip workflows you don’t want backed up (like the backup workflow itself).
Bidirectional Sync: Advanced Patterns
Basic backup is one-directional: n8n to Git. Bidirectional sync adds the reverse direction, letting you restore or update n8n from Git. This enables disaster recovery and multi-instance synchronization.
When You Need Bidirectional Sync
Disaster recovery. Your n8n database is corrupted or lost. Pull all workflows from Git to rebuild.
Multi-instance sync. Run development and production instances that need to stay synchronized through Git as the single source of truth.
Migration. Move workflows between n8n instances (cloud to self-hosted, old server to new server) using Git as the transfer mechanism.
Timestamp Comparison Logic
The tricky part of bidirectional sync is conflict detection. When workflows exist in both n8n and Git, which version is authoritative?
The safest approach: compare updatedAt timestamps.
// In a Code node after fetching both versions
const n8nUpdated = new Date($('n8n Workflow').item.json.updatedAt);
const gitUpdated = new Date($('Parse Git File').item.json.updatedAt);
if (n8nUpdated > gitUpdated) {
// n8n version is newer - push to Git
return { action: 'push' };
} else if (gitUpdated > n8nUpdated) {
// Git version is newer - pull to n8n
return { action: 'pull' };
} else {
// Same timestamp - skip
return { action: 'skip' };
}
Conflict Resolution Strategies
When the same workflow is edited in both places simultaneously, you have a conflict. Options:
Last writer wins. The most recent change overwrites the other. Simple but can lose work.
Git wins. Always prefer the Git version. Makes Git the authoritative source.
n8n wins. Always prefer the n8n version. Makes n8n the authoritative source, Git is just backup.
Manual intervention. Flag conflicts for human review. Safest but requires attention.
For most teams, making Git the authoritative source works well. Changes flow through Git, and n8n instances pull from it. This matches how software development typically works.
Sync Workflow Pattern
A bidirectional sync workflow typically:
- Fetches all workflows from n8n via API
- Fetches all workflow files from Git repository
- Compares by workflow ID and timestamp
- Pushes newer n8n workflows to Git
- Pulls newer Git workflows to n8n via API import
- Reports any conflicts
This is complex to build from scratch. Start with the backup workflow above, then add the reverse direction once backups are stable.
CI/CD Pipeline Integration
Treating workflows as code enables automated deployment pipelines. Merge changes in Git, and they automatically deploy to your n8n instances.
GitHub Actions for n8n Deployment
Here’s a GitHub Actions workflow that triggers an n8n pull after merging to main:
name: Deploy to n8n Production
on:
push:
branches:
- main
paths:
- 'workflows/**'
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Trigger n8n Pull
run: |
curl --request POST \
--url "${{ secrets.N8N_URL }}/api/v1/source-control/pull" \
--header "Content-Type: application/json" \
--header "X-N8N-API-KEY: ${{ secrets.N8N_API_KEY }}" \
--data '{"force": true}'
This requires:
N8N_URLsecret with your n8n instance URLN8N_API_KEYsecret with an n8n API key- n8n Enterprise with source control configured
GitLab CI/CD Example
The equivalent GitLab CI configuration:
deploy-production:
stage: deploy
only:
- main
changes:
- workflows/**
script:
- |
curl --request POST \
--url "$N8N_URL/api/v1/source-control/pull" \
--header "Content-Type: application/json" \
--header "X-N8N-API-KEY: $N8N_API_KEY" \
--data '{"force": true}'
Environment Promotion Pipeline
For multi-environment setups, create a promotion pipeline:
- Development - Developers push to
developbranch, triggers pull to dev n8n - Staging - Merge
developtostaging, triggers pull to staging n8n - Production - Merge
stagingtomain, triggers pull to production n8n
Each environment has its own n8n instance connected to its branch. Changes flow through the pipeline with approval gates at each merge.
Validation Before Deployment
Add validation steps before deploying:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate JSON Syntax
run: |
for file in workflows/*.json; do
jq empty "$file" || exit 1
done
- name: Check Required Fields
run: |
for file in workflows/*.json; do
jq -e '.name and .nodes' "$file" || exit 1
done
This catches malformed JSON and missing required fields before they break your n8n instance.
Multi-Environment Setup
Production-ready n8n deployments separate development from production. This section covers patterns for managing multiple environments with Git.
Environment Architecture
The typical setup includes three environments:
| Environment | Purpose | Branch | Instance |
|---|---|---|---|
| Development | Building and testing | develop | dev.n8n.yourcompany.com |
| Staging | Pre-production validation | staging | staging.n8n.yourcompany.com |
| Production | Live workflows | main | n8n.yourcompany.com |
Each environment is a separate n8n instance with its own database, connected to its corresponding Git branch.
Branch Protection Rules
Configure Git to protect your production branches:
Main branch:
- Require pull request reviews
- Require status checks to pass
- No direct pushes
- No force pushes
Staging branch:
- Require pull request from develop
- Optional reviews
- Status checks for validation
Develop branch:
- Developers can push directly
- Fast iteration allowed
This ensures changes flow through proper review before reaching production.
Credential Management Across Environments
Workflows sync between environments, but credentials don’t. This is intentional - development and production should use different API keys, database connections, and service accounts.
When you push a workflow, n8n exports credential references (IDs), not actual secrets. Each environment has its own credentials with matching IDs.
Setup approach:
- Create credentials in each environment with the same names
- n8n will match by credential ID during import
- If IDs don’t match, manually map credentials after import
For credential best practices across environments, see our environment variables guide.
Environment-Specific Variables
Use n8n’s Variables feature for environment-specific configuration:
API_BASE_URL- Different between dev/staging/prodNOTIFICATION_EMAIL- Dev sends to test inboxDEBUG_MODE- Enabled in dev, disabled in prod
Variables are part of source control, so you can push different values per branch.
Troubleshooting Common Issues
Git integration introduces new failure modes. Here are the issues n8n users encounter most often, with solutions.
Problem: Git Push Fails with Authentication Error
Symptoms: Execute Command node or Git node fails with “Permission denied” or “Authentication failed”.
Causes and Solutions:
1. SSH keys not mounted (Docker)
When running n8n in Docker, the container doesn’t have access to your host’s SSH keys.
# Mount SSH directory when running n8n
docker run -it \
-v ~/.ssh:/home/node/.ssh:ro \
-v n8n_data:/home/node/.n8n \
n8nio/n8n
Or create dedicated keys for n8n:
# Generate keys for n8n
ssh-keygen -t ed25519 -f ./n8n_ssh_key -N ""
# Mount in container
docker run -it \
-v $(pwd)/n8n_ssh_key:/home/node/.ssh/id_ed25519:ro \
-v $(pwd)/n8n_ssh_key.pub:/home/node/.ssh/id_ed25519.pub:ro \
n8nio/n8n
2. Personal Access Token issues
For HTTPS, ensure your token has correct scopes:
- GitHub:
reposcope (full repository access) - GitLab:
apiorwrite_repositoryscope
3. Use GitHub node instead of Execute Command
The GitHub node handles authentication internally. If Execute Command git push fails, switch to using the GitHub node’s Create/Edit file operations.
For Docker-specific issues, our Docker setup guide covers container configuration in detail.
Problem: Workflows Out of Sync
Symptoms: Workflow in n8n doesn’t match what’s in Git. Changes seem lost.
Causes and Solutions:
1. Pull didn’t happen
Check if your pull workflow or trigger actually ran. Verify n8n execution logs.
2. Force pull required
When there are conflicts, normal pull may fail silently. Use force pull:
curl --request POST \
--url '<YOUR-INSTANCE-URL>/api/v1/source-control/pull' \
--header 'Content-Type: application/json' \
--header 'X-N8N-API-KEY: <YOUR-API-KEY>' \
--data '{"force": true}'
3. Wrong branch connected
Verify the n8n instance is connected to the expected branch in Source Control settings.
4. Workflow ID mismatch
If workflows were created independently in n8n and Git, they have different IDs. They won’t sync automatically. You need to:
- Export from one source
- Delete from the other
- Import with the correct ID
Problem: Credentials Not Working After Sync
Symptoms: Workflows import successfully but fail with credential errors.
Causes and Solutions:
1. Encryption key mismatch
All n8n instances must use the same encryption key to share credentials. If keys differ, one instance can’t decrypt credentials from another.
# Ensure this is identical across all instances
N8N_ENCRYPTION_KEY=your-32-byte-hex-key
Generate a key once, use everywhere. See our self-hosting mistakes guide for more on encryption key management.
2. Credential stubs only
Git backup includes credential stubs (references), not actual secrets. You must create matching credentials in each environment manually.
3. Credential ID mismatch
If credentials have different IDs between environments, workflows won’t find them after import. Either:
- Recreate credentials with matching IDs
- Update workflow JSON to reference correct credential IDs
- Map credentials manually in the n8n UI after import
Problem: Backup Workflow Itself Gets Backed Up
Symptoms: Infinite loop or the backup workflow appears in your Git repository.
Solution:
Add a Filter node to exclude the backup workflow by name:
// Filter expression
{{ $json.name !== 'Backup All Workflows to GitHub' }}
Or exclude by workflow ID if the name might change.
Best Practices for n8n Git Automation
Follow these practices to maintain a healthy Git-based workflow management system.
| Practice | Description |
|---|---|
| Commit frequently | Save after every meaningful change, not just at end of day |
| Write descriptive messages | ”Add customer notification on order complete” not “update” |
| Use branches for features | Don’t develop directly on main/production |
| Test before merge | Validate in staging environment first |
| Never store secrets in Git | Use n8n credentials store, not hardcoded values |
| Automate backups | Don’t rely on remembering to export manually |
| Monitor backup success | Alert when backup workflows fail |
| Document your workflows | Add sticky notes explaining complex logic |
| Review before deploy | Have another person check production changes |
| Keep repositories organized | Use folders: /workflows, /credentials, /docs |
Key Insight: The goal isn’t just backup - it’s creating a professional development workflow where changes are tracked, reviewed, tested, and deployed systematically.
For production workflow patterns, our workflow best practices guide covers error handling, testing, and maintainability.
Real-World Implementation Examples
Example 1: Solo Developer Backup
Situation: Freelancer running self-hosted n8n, wants protection against data loss.
Solution:
- Daily backup workflow to private GitHub repo
- GitHub node for simplicity (no SSH setup)
- Weekly retention with older backups archived
Time to implement: 1 hour
Example 2: Agency Multi-Client Setup
Situation: Digital agency managing n8n workflows for multiple clients. Need separation and audit trails.
Solution:
- Separate Git repository per client
- All workflows tagged with client name
- Backup workflow filters by tag, pushes to correct repo
- Monthly compliance reports generated from Git history
Time to implement: 4-6 hours
For agency operations, our workflow development services can help design multi-client architectures.
Example 3: Enterprise CI/CD Pipeline
Situation: Large organization with dev/staging/prod environments. Need controlled deployments with approvals.
Solution:
- n8n Enterprise with native source control
- Three instances connected to respective branches
- GitHub Actions for automated deployment after merge
- Slack notifications on deployment success/failure
- Rollback workflow ready for emergencies
Time to implement: 1-2 days
For enterprise deployments, our consulting services provide architecture guidance and implementation support.
When to Get Professional Help
Git automation setup is straightforward for experienced DevOps engineers. But not every team has that expertise.
Consider professional help when:
- Your team lacks Git or Docker experience
- You’re setting up enterprise multi-environment pipelines
- Compliance requirements mandate specific audit trails
- You need to migrate from manual exports to automated backup
- Integration with existing CI/CD systems is complex
Our n8n support services include infrastructure setup, monitoring, and ongoing maintenance.
Frequently Asked Questions
Can I use Git with n8n Community Edition?
Yes, through custom backup workflows. The native source control feature requires Enterprise, but you can build backup workflows using the GitHub, GitLab, or Git nodes in any n8n version. The main difference is that native source control provides a UI in n8n for push/pull operations, while custom workflows run on schedules or triggers.
How often should I backup my n8n workflows?
Daily is the minimum for production workflows. If you make frequent changes, consider running backups every few hours or triggering backups whenever workflows are saved (using n8n’s internal events as triggers). The GitHub API has rate limits, so extremely frequent backups may need throttling.
What happens if two people edit the same workflow simultaneously?
Without proper branching, last push wins. The second person’s changes overwrite the first person’s work. To prevent this:
- Use Git branches - each person works on their own branch
- Merge through pull requests with conflict detection
- Pull latest changes before starting work
- Communicate about who’s working on which workflow
Native source control doesn’t handle merging - you need to do that in your Git provider.
Can I restore a single workflow from Git backup?
Yes. Download the specific workflow JSON file from your Git repository, then import it using n8n’s UI (Settings > Import from File) or via the n8n API. You can also use the n8n node’s “Create Workflow” operation to programmatically import:
// POST to n8n API
{
"name": "Restored Workflow",
"nodes": [...],
"connections": {...}
}
Does Git backup include my credentials and secrets?
Only credential stubs - references to credentials by ID, not actual secrets. Your API keys, passwords, and tokens stay in n8n’s encrypted credential store. This is a security feature. When restoring to a new instance, you’ll need to recreate credentials with matching IDs, or update the workflow to reference new credential IDs.
For secure credential handling, see our credential management guide.