Importing Kibana saved objects lets you move dashboards, data views, saved searches, and other workspace assets between environments without rebuilding them by hand. A clean import path keeps dashboards reproducible across development, staging, and production when the same views need to be promoted into another Kibana space or deployment.
Kibana stores these assets as saved object documents and imports them from a file created by the Saved Objects export API or the Saved Objects page in the web UI. The import endpoint accepts an NDJSON file as multipart form data, runs the saved-object migrations needed for the current version, and can either overwrite matching objects or create new copies with regenerated IDs.
Current Kibana releases import saved objects only into the same version, a newer minor on the same major, or the next major. The account performing the import needs the Saved Objects Management Kibana privilege, import requests must include the kbn-xsrf header, and large files are still limited by savedObjects.maxImportExportSize and savedObjects.maxImportPayloadBytes. When objects are imported into another space or as new copies, Kibana can assign different IDs, which can break weak links such as Markdown links that still point to old dashboard URLs.
Related: How to export Kibana saved objects
Related: How to create a Kibana space
$ curl --silent --show-error --fail \
--user 'kibana_import:password' \
--cacert /etc/kibana/certs/http-ca.crt \
'https://kibana.example.net:5601/api/status' | jq '{version: .version.number, status: .status.overall.level}'
{
"version": "9.3.2",
"status": "available"
}
Importing works only into the same Kibana version, a newer minor on the same major, or the next major. Add the configured base path before /api/ when Kibana is published behind a reverse proxy, such as https://kibana.example.net:5601/kibana/api/status.
Related: How to check Kibana status
$ head -n 2 saved-objects.ndjson
{"attributes":{"description":"Imported dashboard example","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}"},"optionsJSON":"{\"useMargins\":true,\"hidePanelTitles\":false}","panelsJSON":"[]","timeRestore":false,"title":"Ops overview"},"coreMigrationVersion":"8.8.0","created_at":"2026-04-02T13:52:47.850Z","id":"ops-overview","managed":false,"references":[],"type":"dashboard","typeMigrationVersion":"10.3.0","updated_at":"2026-04-02T13:52:47.850Z","version":"WzYsMV0="}
{"attributes":{"allowHidden":false,"allowNoIndex":true,"fieldAttrs":"{}","fieldFormatMap":"{}","fields":"[]","name":"Ops import logs","runtimeFieldMap":"{}","sourceFilters":"[]","timeFieldName":"@timestamp","title":"ops-import-*"},"coreMigrationVersion":"8.8.0","created_at":"2026-04-02T13:52:48.104Z","id":"388b3515-36a8-4d0d-84a6-ca7785b3499e","managed":false,"references":[],"type":"index-pattern","typeMigrationVersion":"8.0.0","updated_at":"2026-04-02T13:52:48.104Z","version":"WzcsMV0="}
Use a file exported from Kibana rather than hand-editing the NDJSON. The saved objects APIs still use the saved object type index-pattern for data views in export and import payloads.
$ curl --silent --show-error --fail \
--user 'kibana_import:password' \
--cacert /etc/kibana/certs/http-ca.crt \
--header 'kbn-xsrf: true' \
--form file=@saved-objects.ndjson \
'https://kibana.example.net:5601/s/ops-import/api/saved_objects/_import?overwrite=true' | jq '{success: .success, successCount: .successCount, successResults: [.successResults[] | {type: .type, id: .id, title: .meta.title}]}'
{
"success": true,
"successCount": 2,
"successResults": [
{
"type": "dashboard",
"id": "ops-overview",
"title": "Ops overview"
},
{
"type": "index-pattern",
"id": "388b3515-36a8-4d0d-84a6-ca7785b3499e",
"title": "Ops import logs"
}
]
}
Using overwrite=true replaces matching objects in the target space. Use createNewCopies=true when you need side-by-side copies instead, but do not combine it with overwrite or compatibilityMode.
Use compatibilityMode=true only when Kibana reports import compatibility problems, and replace --user with an Authorization: ApiKey header when automation already standardizes on API key authentication.
$ curl --silent --show-error --fail \
--user 'kibana_import:password' \
--cacert /etc/kibana/certs/http-ca.crt \
'https://kibana.example.net:5601/s/ops-import/api/saved_objects/_find?type=dashboard&search_fields=title&search=Ops%20overview&per_page=1' | jq '{total: .total, saved_objects: [.saved_objects[] | {id: .id, type: .type, title: .attributes.title}]}'
{
"total": 1,
"saved_objects": [
{
"id": "ops-overview",
"type": "dashboard",
"title": "Ops overview"
}
]
}
If the import response reports success: false, inspect the errors array for conflict or missing_references details. Objects are created only after Kibana can resolve every import error for that object set.
Current Kibana imports overwrite matching objects by default in the web UI. Use Create new objects with random IDs only when you explicitly want copies with new IDs, and check dashboard links afterward because ID changes can break weak links.