Files
dify/docs/cross-env-app-migration/README.md
Blackoutta 0c40e1c2a0 feat: add cross-environment app migration workflow (#36765)
Co-authored-by: XW <wei.xu1@wiz.ai>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-05-28 07:30:33 +00:00

14 KiB

Cross-Environment Data Migration

This guide explains how to move workflow apps, chatflow apps, and their custom tool dependencies from one Dify environment to another.

The recommended best-practice path is:

  1. Run the export wizard in the source environment.
  2. Import the generated migration package in the target environment.

Use scripted export only when you need repeatable automation.

What Gets Migrated

The migration package can contain:

  • Workflow apps and advanced-chat apps.
  • Custom API tool providers.
  • Workflow tool providers.
  • MCP tool providers when secrets are explicitly included.
  • Dependency metadata for MCP tools, built-in tools, and plugin tools that must already exist or be configured in the target environment.

Only single source workspace exports are supported. The source and target workspace names do not need to match.

Run the wizard from the source environment:

cd api
source .venv/bin/activate
uv run flask app-migration-wizard

The wizard asks you to select the source workspace, choose workflow/chatflow apps, discover referenced tools, set import behavior, and write the final migration package JSON.

Then copy the generated JSON package to the target environment and import it:

cd api
source .venv/bin/activate
uv run flask import-app-migration \
  --input migration-data-20260528-120000.json \
  --target-tenant "production Workspace"

This wizard + import combination is the recommended migration workflow because the wizard shows the available apps and tools, discovers app dependencies, summarizes the package before writing it, and uses the same export service as scripted export.

Wizard Command

cd api
source .venv/bin/activate
uv run flask app-migration-wizard

The wizard has no CLI options. Its interactive inputs are:

  • Source tenant: the source workspace to export from. Select one tenant by number.
  • App selection: apps to export. Supported app types are workflow and advanced-chat. Enter all, one number, or comma-separated numbers.
  • Automatically export tools referenced by selected apps?: recommended yes. This scans selected app graphs and automatically includes referenced custom API tools, workflow tools, and MCP tool references.
  • Export additional tools manually?: optional. Use this when you need to migrate tools that are not referenced by the selected apps.
  • Include secrets in output JSON?: default no. When no, workflow/app DSL secrets are omitted or masked, API tool credentials are omitted, and MCP providers are exported as dependency metadata only. When yes, treat the output JSON as sensitive.
  • Create or reuse app API tokens during import?: default no. When yes, import creates an app API token for imported apps that have none, or reuses an existing token.
  • Import ID strategy: preserve-id or generate-new-id. Default is preserve-id.
  • Import conflict strategy: fail, skip, or update. Wizard default is update.
  • Output path: output migration package path. The default is migration-data-YYYYMMDD-HHMMSS.json.
  • Overwrite existing output: shown only if the selected output file already exists.
  • Write migration package?: final confirmation after the wizard prints the summary.

Import Command

cd api
source .venv/bin/activate
uv run flask import-app-migration --input migration-package.json --target-tenant "target Workspace"

Options:

  • --input: required. Path to the migration package JSON generated by the wizard or scripted export.
  • --target-tenant: optional only when package metadata already contains a target tenant. Target workspace name or workspace UUID. This overrides package metadata and is recommended for reusable packages.
  • --operator-email: optional. Email of the target-tenant account used as the import operator. If omitted, import uses the earliest owner account in the target tenant.
  • --id-strategy: optional override for the package import option. Allowed values:
    • preserve-id: keep source app/tool IDs when supported. This is the recommended default for preserving workflow references across environments.
    • generate-new-id: let the target environment generate new IDs and rewrite references through the migration ID mapping.
  • --conflict-strategy: optional override for the package import option. Allowed values:
    • fail: stop at the first existing target resource conflict. Previously committed resources are not rolled back.
    • skip: keep the existing target resource and skip importing that resource.
    • update: update the existing target resource in place.
  • --create-app-api-token-on-import: optional override. Create or reuse app API tokens during import.
  • --no-create-app-api-token-on-import: optional override. Do not create app API tokens during import.

Import prints a report that includes the resolved target tenant, operator, created/updated/skipped resources, unresolved dependencies, app API token counts, and ID mappings used to rewrite references.

Optional Flow: Scripted Export

Scripted export is supported for automation. The recommended scripted path is:

  1. Generate an export config template.
  2. Edit the template.
  3. Run scripted export.
  4. Import the generated package.

Generate the template:

cd api
source .venv/bin/activate
uv run flask app-migration-template --output export-config.json

Edit export-config.json, then run:

cd api
source .venv/bin/activate
uv run flask export-app-migration \
  --input export-config.json \
  --output migration-package.json

Import it:

cd api
source .venv/bin/activate
uv run flask import-app-migration \
  --input migration-package.json \
  --target-tenant "production Workspace"

Template Command

cd api
source .venv/bin/activate
uv run flask app-migration-template [--output export-config.json] [--overwrite]

Options:

  • --output: optional. Path to write the scripted export config JSON template. If omitted, the template is printed to stdout.
  • --overwrite: optional. Allows replacing an existing output file. Without this option, the command fails if --output already exists.

Scripted Export Command

cd api
source .venv/bin/activate
uv run flask export-app-migration --input export-config.json --output migration-package.json

Options:

  • --input: required. Path to the export config JSON.
  • --output: required. Path to write the migration package JSON.
  • --overwrite: optional. Allows replacing an existing output package. Without this option, the command fails if --output already exists.

Export Config Fields

The generated template uses this shape:

{
  "source_tenant": {
    "mode": "single",
    "id": "",
    "name": "admin's Workspace"
  },
  "apps": {
    "modes": ["workflow", "advanced-chat"],
    "ids": [],
    "all": true
  },
  "include_referenced_tools": true,
  "additional_tools": {
    "api_tools": [],
    "workflow_tools": [],
    "mcp_tools": []
  },
  "include_secrets": false,
  "import_options": {
    "create_app_api_token_on_import": false,
    "id_strategy": "preserve-id",
    "conflict_strategy": "fail"
  }
}

Fields:

  • source_tenant.mode: must be single.
  • source_tenant.id: optional source workspace UUID. Use this when workspace names are duplicated or when you want strict source selection.
  • source_tenant.name: required source workspace name. When source_tenant.id is set, the ID and name must match.
  • apps.modes: optional list of app modes for validation. Supported values are workflow and advanced-chat.
  • apps.ids: app IDs to export when apps.all is false.
  • apps.all: when true, export all supported apps in the selected source workspace. When false, export only apps.ids.
  • include_referenced_tools: recommended true. Automatically discovers tools referenced by selected workflow/chatflow apps.
  • additional_tools.api_tools: optional custom API tool provider names to export in addition to referenced tools.
  • additional_tools.workflow_tools: optional workflow tool provider IDs to export in addition to referenced tools.
  • additional_tools.mcp_tools: optional MCP provider IDs or server identifiers to export in addition to referenced tools.
  • include_secrets: default false. When false, credentials are omitted and MCP providers are recorded as dependency metadata. When true, custom API credentials, workflow DSL secrets, and full MCP connection data can be written to the package.
  • import_options.create_app_api_token_on_import: default false. Package-level default for import token creation.
  • import_options.id_strategy: package-level default ID strategy. Allowed values are preserve-id and generate-new-id.
  • import_options.conflict_strategy: package-level default conflict strategy. Allowed values are fail, skip, and update.

Referenced Tools

Use automatic referenced-tool discovery whenever possible.

When enabled, Dify scans selected workflow/chatflow graphs and agent tool configs, then de-duplicates discovered custom API tools, workflow tools, and MCP tool references before export. This reduces the chance of importing an app whose workflow references missing providers.

Built-in and plugin tools are not serialized into the package. The migration report records them as dependency metadata; make sure the target environment has the required built-in or plugin tools installed and configured.

MCP providers are also dependency-only unless include_secrets is enabled. If MCP secrets are not exported, configure the corresponding MCP provider manually in the target workspace before running migrated workflows.

Secret Handling

The safe default is include_secrets: false.

Only enable secret export when you have a controlled transfer path for the JSON package. With secrets enabled, the package may include API tool credentials, workflow/app DSL secret values, MCP server URLs, MCP headers, authentication data, and cached MCP tool lists.

FAQ

What happens when include_secrets is false?

This is the recommended default, but it means the migration package is intentionally incomplete for sensitive runtime configuration.

Important behavior:

  • MCP tools are not exported as full tool providers. They are recorded as dependency metadata only.
  • Custom API tool credentials are not exported. The provider schema can be exported, but credentials must be configured again in the target workspace.
  • Workflow/app DSL secrets are omitted or masked. Any app variables, credentials, or secret-backed settings must be reviewed in the target workspace after import.
  • Built-in and plugin tools are never serialized as custom migration data. They are recorded as dependencies only.

How to handle it:

  • Before importing, install or enable the required built-in/plugin tools in the target environment.
  • For MCP tools, manually create or configure the corresponding MCP provider in the target workspace before running migrated workflows.
  • For custom API tools, open the imported provider in the target workspace and re-enter credentials.
  • After import, review each migrated workflow/chatflow before production use. Pay special attention to tool nodes, agent tool configs, environment variables, app variables, and credential-backed settings.
  • Use the import report. Items marked dependency-only, skipped, or unresolved usually need manual follow-up.

If you need the package to carry full MCP provider configuration or credentials, rerun export with include_secrets set to true and transfer the generated JSON as sensitive data.

What should I consider when include_secrets is true?

The package can include sensitive runtime configuration such as API tool credentials, workflow/app DSL secret values, MCP server URLs, headers, authentication data, and MCP tool lists.

How to handle it:

  • Store and transfer the JSON package as a secret.
  • Delete the package after import if your security policy requires it.
  • Prefer using this only for controlled one-time migrations where manual target-side credential setup is harder than securing the package.

Should I use preserve-id or generate-new-id?

The ID strategy controls whether imported resources keep source IDs or receive new IDs in the target environment. It applies to workflow apps and custom tool resources where the target service supports explicit IDs.

Use preserve-id by default. It is recommended for cross-environment app migration because imported apps and tools try to keep their source IDs, which makes workflow references easier to preserve.

Use preserve-id when:

  • You are migrating between environments that are meant to mirror each other, such as staging to production.
  • You want workflow tool references and provider references to remain as stable as possible.
  • The target environment does not already contain unrelated resources with the same IDs.

Watch out for:

  • If the target already has a resource with the same ID, conflict_strategy=fail stops the import, skip keeps the target resource, and update updates it in place.
  • If the same ID was reused for a different resource in the target environment, review carefully before using update.

Use generate-new-id when the target environment should keep its own local IDs.

Use generate-new-id when:

  • The target environment already has resources that may conflict with source IDs.
  • You are importing a package as a copy rather than trying to mirror environments.
  • You want to avoid preserving source database IDs in the target environment.

Watch out for:

  • Import records source-to-target ID mappings. Always review the import report's ID mappings.
  • Workflow DSL provider references are rewritten using the generated ID mapping where possible.
  • Dependencies that are metadata-only, such as MCP providers exported with include_secrets=false, still require manual target-side configuration.
  • Built-in/plugin tools are not remapped as migrated custom resources; the target environment must provide them separately.