Configuration

JSON Import and Export

Export a menu to JSON when you want a backup or need to copy its settings and links to another environment. Importing the file can create a separate menu or replace an existing menu you choose.

For CSV or XML content, use Feed Me. If the menus already belong to another plugin, choose its guide under Migrations & Upgrades before exporting anything.

Control Panel

Go to Navigation → Settings → Import/Export (/admin/navigation/settings/import-export).

  1. Import Menu — upload a JSON file, review the console-style summary on the next screen, then import
  2. Export Menu — pick a menu from the dropdown and download JSON

Import is a settings-level workflow, not something you do while editing a menu. The file describes a whole menu; Navigation either creates a new one or — if you explicitly choose to — updates an existing menu with the same handle.

When a handle already exists, you must choose:

  • Create a new menu — generates a unique handle (mainMenu1, etc.). Safest default for staging → production.
  • Update existing menu — overwrites settings and replaces the entire node tree. Destructive; use when syncing a known menu in place.

After import you land on an Import Completed screen with a link to the menu builder.

Console

# List menus and JSON files in the export folder
php craft navigation/import-export/list

# Export
php craft navigation/import-export/export-json mainMenu
php craft navigation/import-export/export-json mainMenu --path=./mainMenu.json

# Import (creates a new menu when the handle already exists)
php craft navigation/import-export/import-json ./mainMenu.json

# Import and overwrite an existing menu by handle
php craft navigation/import-export/import-json ./mainMenu.json --update

Default export folder: @storage/navigation-exports.

Control-panel and console exports include independent branches from every site, with shared nodes included once. Each node records its source site handle so an import can recreate site-specific branches. Keep the same site handles in the destination environment.

Export Format

{
  "exportVersion": "1.0.0",
  "exportedAt": "2026-07-03T00:00:00+00:00",
  "sourceSiteHandle": "default",
  "menu": {
    "name": "Main Menu",
    "handle": "mainMenu",
    "propagationMethod": "all",
    "siteSettings": { "default": { "enabled": true } }
  },
  "menuFieldValues": {
    "default": { "promoHeading": "Shop now" }
  },
  "nodes": [
    {
      "title": "About",
      "type": "verbb\\navigation\\nodetypes\\Custom",
      "url": "/about",
      "newWindow": false,
      "children": []
    }
  ]
}

Portability Rules

DataExport strategy
Linked Craft elementslinkedElementUid + linkedElementType
Site links and built-in Dynamic sourcessourceHandle resolves the selected site, section, category group, asset volume, or product type
Per-site URLs, suffixes, titles, enabled states, and node fieldssiteOverrides keyed by site handle
Menu field valuesmenuFieldValues keyed by site handle
Node custom fieldsfieldValues keyed by field handle
Node typesRegistered node type class name

Exports include the node and menu field layouts. The destination must already have the referenced global fields with matching UIDs, normally supplied by the same Craft project config. Import creates independent layouts for the new menu; it does not create global fields or install field-type plugins.

Linked content must exist on the destination site. An unresolved element UID produces a warning, and an element-backed node without its required link fails validation. The import rolls back: a new menu is not created, and an existing menu remains unchanged. Restore or migrate the linked content, then retry the import.

Site links and built-in Dynamic nodes require matching source handles on the destination. A missing source stops the import and preserves existing content. Older exports without sourceHandle retain database IDs and can be restored to the same database; export them again from the source environment before moving them to a different database. Data belonging to custom node types or Dynamic providers is preserved as supplied.

Developer API

use verbb\navigation\helpers\ImportExportHelper;
use verbb\navigation\Navigation;

$menu = Navigation::$plugin->getMenus()->getMenuByHandle('mainMenu');
$export = ImportExportHelper::generateMenuExport($menu);

// For an existing site with the handle `french`, export only its tree.
$site = Craft::$app->getSites()->getSiteByHandle('french');
$siteExport = ImportExportHelper::generateMenuExport($menu, $site->id);

$result = ImportExportHelper::importMenuFromJson($json, 'create'); // or 'update'

See ImportExportHelper for the format details and import report (MenuImportResult).

The optional $siteId is the ID of an existing Craft site. A site-scoped export contains only that site's nodes; importing it with update still replaces the entire menu tree. Use the default whole-menu export for backups.