You signed up for n8n Cloud because it was the fastest path to running workflows. No server to manage, no Docker to configure, no SSL certificates to provision. That made sense at the start. But now you are hitting execution limits, the monthly bill is climbing past the cost of dedicated infrastructure, or you need your workflow data to stay within a specific jurisdiction. The next step is migrating to a self-hosted instance — and doing it without losing a single workflow or breaking a single webhook.

This guide covers the complete migration from n8n Cloud to a self-hosted n8n instance running on your own VPS. The process takes about an hour of active work, plus a few hours of monitoring to confirm everything is stable. The hardest part is not the technical migration itself — it is the credential reconfiguration, because n8n Cloud and your self-hosted instance use different encryption keys. Every API key, OAuth token, and database credential needs to be re-entered manually.

If you do not already have a self-hosted n8n instance running, follow our complete Docker setup guide first. This guide assumes you have a working n8n instance with PostgreSQL and Caddy ready to receive your imported workflows.

When to Migrate Off n8n Cloud

Not every n8n Cloud user needs to migrate. The Cloud product is genuinely good for teams that want zero infrastructure management and have moderate workflow volume. But there are clear signals that self-hosting will serve you better:

  • You are hitting execution limits. n8n Cloud's Starter plan caps at 2,500 executions per month for €24. The Pro plan raises that to 10,000 for €60. If your workflows routinely exceed these thresholds, you are either paying overage fees or throttling your automation. A self-hosted instance has zero execution limits — the only ceiling is your server's hardware.
  • Cost is scaling faster than value. At 50,000 executions per month on Cloud, you are looking at €60–120+/month depending on your plan tier. The same workload on a self-hosted VPS costs $9.58–$19.16/month with no per-execution pricing.
  • Data residency matters. n8n Cloud processes data through n8n's infrastructure. If you need workflow data, credentials, and execution logs to stay within a specific geographic jurisdiction — EU for GDPR, or a specific country for sectoral regulations — self-hosting on a VPS in that jurisdiction is the only way to guarantee it.
  • You want full control over updates. n8n Cloud updates automatically. Most of the time this is fine. Occasionally an update changes behavior in a way that breaks a workflow. Self-hosting lets you pin to a specific version and update on your own schedule after testing.
  • You need custom nodes or community packages. n8n Cloud restricts which community nodes you can install. Self-hosted instances have no such restriction.

If none of these apply to you, n8n Cloud is probably still the right choice. This guide is for the users where one or more of these pain points has become real enough to justify the migration effort.

What Transfers and What Doesn't

Before you start, understand exactly what moves cleanly and what requires manual work:

Transfers cleanly

  • Workflow definitions — All node configurations, connections, and settings export as JSON. Every workflow you have built will import into your self-hosted instance with its structure completely intact.
  • Workflow tags and organization — Tags and folder structure are preserved in the export.
  • Static workflow data — Any hardcoded values, expressions, and workflow-level variables come through in the JSON export.

Requires manual reconfiguration

  • Credentials — This is the biggest manual task. n8n encrypts all credentials with an instance-specific encryption key (N8N_ENCRYPTION_KEY). Your Cloud instance and your self-hosted instance have different encryption keys, so credentials cannot be decrypted after import. Every API key, OAuth connection, database credential, and SMTP configuration must be re-entered manually on the self-hosted instance.
  • Webhook URLs — Every webhook trigger in your workflows has a URL that includes your n8n Cloud domain (e.g., your-instance.app.n8n.cloud/webhook/...). After migration, these URLs change to your self-hosted domain (e.g., n8n.yourdomain.com/webhook/...). You need to update every external service that sends webhooks to your n8n instance.

Does not transfer

  • Execution history — Past execution data stays on n8n Cloud. It does not export with workflows. If you need historical execution data for auditing, export it separately or screenshot the relevant executions before deactivating your Cloud account.
  • User accounts and permissions — If you have multiple users on your Cloud instance, you will need to recreate their accounts on the self-hosted instance.

Pre-Migration Checklist

Spend 15 minutes on this before touching any export buttons. Skipping this step is how people end up locked out of third-party services mid-migration.

1. Document every credential

Go to Settings → Credentials in your n8n Cloud instance. For each credential, note:

  • The service name (e.g., Stripe, Slack, Google Sheets)
  • The authentication type (API key, OAuth2, basic auth)
  • Where to find or regenerate the key/token (the service's developer dashboard)

You cannot view stored credential values in n8n's UI — they are encrypted at rest. If you do not have the original API keys saved elsewhere, you will need to regenerate them from each service's dashboard after migration.

2. List all webhook URLs

Open every workflow that uses a Webhook trigger node. Copy the production webhook URL. After migration, you will need to update these URLs in every external service that sends data to n8n — Stripe webhook settings, GitHub webhook configurations, form submission endpoints, CRM integrations, and so on.

3. Note active schedules

Record which workflows run on schedules (Cron or Interval trigger nodes) and their timing. After import, you will reactivate these on the self-hosted instance. Verify that timezone settings match — your Cloud instance and self-hosted instance may default to different timezones if you do not set GENERIC_TIMEZONE explicitly in your Docker configuration.

4. Verify your self-hosted instance is ready

Confirm that your target self-hosted n8n instance is fully operational:

  • n8n is accessible via HTTPS at your domain
  • PostgreSQL is running and healthy
  • You can create and execute a test workflow
  • Webhook URLs are reachable from the public internet

If you have not set up your self-hosted instance yet, follow our self-hosting guide with Docker Compose — it takes about 30 minutes.

Step-by-Step Migration

The migration follows a six-phase sequence: export from Cloud, import to self-hosted, reconfigure credentials, update webhook URLs, test everything, and finally cut over DNS if applicable.

Phase 1: Export all workflows from n8n Cloud

n8n provides a built-in bulk export. In your Cloud instance:

  1. Go to Workflows in the left sidebar.
  2. Select all workflows (click the checkbox at the top of the list).
  3. Click Export. n8n will download a single JSON file containing every selected workflow.

Alternatively, if you prefer the CLI or need to script the export, use the n8n API:

# Export all workflows via n8n API
curl -s -H "X-N8N-API-KEY: your-cloud-api-key" \
  https://your-instance.app.n8n.cloud/api/v1/workflows \
  | jq '.data' > all-workflows.json
Tip

Generate an API key in your Cloud instance under Settings → API. The API export gives you more control — you can filter by tag, export individual workflows, or automate the process.

Store the exported JSON file somewhere safe. This is your complete workflow backup. If anything goes wrong during migration, you can re-import from this file.

Phase 2: Deactivate workflows on Cloud

Before importing to your self-hosted instance, deactivate all workflows on the Cloud instance. This prevents duplicate execution — you do not want both instances processing the same webhooks or running the same schedules simultaneously.

  1. Go to Workflows, select all.
  2. Click Deactivate.

Do not delete the workflows yet. Keep them on Cloud as a fallback until your self-hosted instance is fully validated.

Phase 3: Import workflows to self-hosted

On your self-hosted n8n instance:

  1. Go to Workflows.
  2. Click Import from File and select your exported JSON.
  3. n8n will create all workflows in an inactive state.

For API-based import:

# Import workflows via n8n API (self-hosted)
for workflow in $(cat all-workflows.json | jq -c '.[]'); do
  curl -s -X POST \
    -H "X-N8N-API-KEY: your-selfhosted-api-key" \
    -H "Content-Type: application/json" \
    -d "$workflow" \
    https://n8n.yourdomain.com/api/v1/workflows
done

After import, verify the workflow count matches. If you had 47 workflows on Cloud, you should have 47 workflows on self-hosted. Open a few workflows and confirm the node structures look correct.

Phase 4: Reconfigure credentials

This is the most time-consuming step. Every credential must be re-entered because the encryption keys differ between instances.

Work through your credential list systematically:

  1. Open a workflow that shows credential errors (nodes will have a red indicator).
  2. Click the affected node, then click the credential dropdown.
  3. Select Create New and enter the API key, OAuth tokens, or other authentication details from your documentation.
  4. For OAuth2 credentials (Google, Slack, Microsoft), you will need to re-authenticate through the OAuth flow. Make sure your self-hosted n8n domain is registered as an authorized redirect URI in the service's developer console.
  5. Repeat for every unique credential across all workflows.
Warning

OAuth2 redirect URIs are the most common migration blocker. If you used your-instance.app.n8n.cloud as the redirect URI in Google Cloud Console, Slack App settings, or similar, you must add https://n8n.yourdomain.com/rest/oauth2-credential/callback as an authorized redirect URI before the OAuth flow will work on your self-hosted instance.

Many workflows share the same credential (e.g., a single Slack credential used across 15 workflows). Once you create the credential on the self-hosted instance, you can assign it to all workflows that need it. The total number of unique credentials to reconfigure is usually much smaller than the number of workflows.

Phase 5: Update webhook URLs in external services

Every external service that sends webhooks to your n8n Cloud instance needs to be pointed at your self-hosted domain instead. The webhook path (the part after the domain) stays the same — only the domain changes:

Before (Cloud) After (Self-Hosted)
your-instance.app.n8n.cloud/webhook/abc123 n8n.yourdomain.com/webhook/abc123
your-instance.app.n8n.cloud/webhook/stripe-events n8n.yourdomain.com/webhook/stripe-events

Go through each service in your webhook list and update the endpoint URL. Common places to check:

  • Stripe — Dashboard → Developers → Webhooks → Edit endpoint URL
  • GitHub — Repository Settings → Webhooks → Edit payload URL
  • Shopify — Settings → Notifications → Webhooks
  • HubSpot — Settings → Integrations → Webhooks
  • Slack — App settings → Event Subscriptions → Request URL
  • Custom applications — Wherever you hardcoded the n8n Cloud webhook URL

Phase 6: Activate and test

With credentials configured and webhook URLs updated, activate your workflows one at a time. Start with your most critical workflows — the ones processing payment events, customer data, or business operations.

For each workflow:

  1. Open the workflow on your self-hosted instance.
  2. Toggle it to Active.
  3. Trigger a test event (send a test webhook, wait for a scheduled trigger, or manually execute).
  4. Verify the execution completes successfully in the Executions tab.
  5. Confirm the output matches what you expected (data written to the correct place, notifications sent, etc.).

Do not activate all workflows at once. If something is misconfigured, you want to catch it on one workflow, not discover 47 broken executions in your logs the next morning.

Info

Some workflows are difficult to test without real data. For webhook-triggered workflows, most services offer a "send test event" feature in their webhook settings. For Stripe, use the Send test webhook button. For GitHub, use the Recent Deliveries → Redeliver option.

Post-Migration Validation

After activating all workflows, monitor your self-hosted instance closely for 48 hours. Here is what to check:

Execution success rate

Go to Executions in the left sidebar. Filter by status. You should see zero failed executions that are not also failing on Cloud (some workflows fail due to upstream API issues regardless of where n8n runs). Any new failures are likely credential issues or webhook URL mismatches.

Webhook delivery confirmation

For critical webhook workflows, check the sending service's webhook logs to verify delivery. Stripe, GitHub, and most SaaS platforms show delivery status, response codes, and retry history. You should see 200 responses from your self-hosted domain.

Scheduled workflow timing

Confirm that Cron and Interval trigger workflows are firing at the expected times. Timezone mismatches are the most common issue here. If your Cloud instance was set to Europe/Berlin but your self-hosted instance defaults to UTC, scheduled workflows will fire at different clock times. Set GENERIC_TIMEZONE in your .env file to match.

Resource utilization

Monitor your VPS resource usage during the first 48 hours. Run htop or docker stats to check CPU and memory consumption. If you migrated a large number of active workflows, you may need more resources than initial testing suggested. On a 2 vCPU / 4 GB VPS, you can comfortably run 20–50 workflows with moderate execution frequency. If you are migrating 100+ workflows or workflows with heavy data processing, consider starting with 4 vCPU / 8 GB ($19.16/mo on MassiveGRID).

Decommission Cloud

Once you are confident the self-hosted instance is handling all workflows correctly (give it at least 48 hours, ideally a full week), you can deactivate your n8n Cloud subscription. Before you do:

  • Take a final export of all workflows from Cloud as a backup archive.
  • Screenshot or export any execution history you want to preserve.
  • Confirm no external services are still pointing webhooks at your Cloud URL.

Cost Savings After Migration

The financial case for migration is straightforward. Here is a concrete example:

n8n Cloud Pro Self-Hosted (MassiveGRID)
Monthly cost €60/mo (~$65) $9.58/mo
Execution limit 10,000/month Unlimited
Configuration Shared infrastructure 2 vCPU / 4 GB / 64 GB SSD
Annual cost ~$780 $114.96 (monthly) or $91.92 (annual billing)
Annual savings $665–$688 per year

For teams running 50,000+ executions on Cloud's higher tiers, the savings are even more significant. A 4 vCPU / 8 GB VPS at $19.16/month handles workloads that would cost €120+/month on Cloud — an annual savings exceeding $1,200.

The cost comparison becomes more dramatic at scale because self-hosted pricing is completely decoupled from execution volume. Whether you run 1,000 executions or 1,000,000 executions in a month, your VPS costs the same. This is fundamentally different from per-execution SaaS pricing, where costs grow linearly (or worse) with usage. For a detailed cost analysis across all major platforms, see our n8n pricing comparison: self-hosted vs Cloud vs Zapier.

Ready to migrate to self-hosted n8n?

High-availability VPS with Proxmox failover, Ceph storage, and 24/7 human support.

Recommended: 2 vCPU / 4 GB RAM / 64 GB SSD — $9.58/mo

Configure Your VPS →