Import and export
Route: /service-topology (Services tab) and the graph editor
A topology can be exported to a JSON file that contains everything the service needs — the topology record, its nodes and edges with their IDs and positions, the weight policies that apply to the service, and the service's catalog entry — and imported back on the same or another ToBeAlert instance without losing anything. Use it to back up a topology before a large restructuring, to copy a service from staging to production, or to keep topologies in version control.
See also: Overview · Topologies · Graph editor · Weight policies · Importing from a CMDB
The web UI calls the export and import endpoints of the Service topology API; everything described here can be scripted.
Export
| Where | Action | What you get |
|---|---|---|
| Services tab, row actions | Export | One file for that topology: topology-<service>-<YYYYMMDD-HHmm>.json |
| Services tab, header | Export all | A bundle with every topology: topologies-<YYYYMMDD-HHmm>.json |
| Graph editor, More actions ▾ | Export | The same single-topology file, for the topology you have open |
The export is always taken from the saved topology. If you are in edit mode with unsaved changes, Save changes first — the file does not include what is only on the canvas.
Characters that are not letters, digits, -, _ or . in the service name are replaced by - in the file name. Each export is recorded in the audit trail (service-topology-exported).
File format
A single-topology export (schemaVersion 2):
{
"kind": "tobealert-service-topology",
"schemaVersion": 2,
"exportedAt": "2026-10-09T10:42:00Z",
"appVersion": "1.12.0",
"topology": {
"id": "3f6a1c2e-8b4d-4e0f-9a71-5c2d7e8f9a01",
"name": "Orders",
"description": "Orders service topology",
"service": "orders",
"serviceKpi": null,
"orientation": "TB"
},
"nodes": [
{
"id": "0d1e2f3a-4b5c-4d6e-8f90-a1b2c3d4e5f6",
"kind": "service",
"label": "orders",
"environment": null,
"resource": null,
"icon": "fa:server",
"params": {},
"hierarchyConfig": {},
"position": { "x": 100, "y": 100 }
},
{
"id": "1e2f3a4b-5c6d-4e7f-9a01-b2c3d4e5f6a7",
"kind": "environment",
"label": "Production",
"environment": "Production",
"resource": null,
"icon": "fa:server",
"params": {},
"hierarchyConfig": {},
"position": { "x": 100, "y": 250 }
},
{
"id": "2f3a4b5c-6d7e-4f80-a112-c3d4e5f6a7b8",
"kind": "resource",
"label": "orders-app",
"environment": "Production",
"resource": "orders-app",
"icon": "fa:server",
"params": {},
"hierarchyConfig": { "disabledHereditary": false },
"position": { "x": 100, "y": 400 }
},
{
"id": "3a4b5c6d-7e8f-4091-b223-d4e5f6a7b8c9",
"kind": "resource",
"label": "orders-db",
"environment": "Production",
"resource": "orders-db",
"icon": "fa:database",
"params": {},
"hierarchyConfig": {},
"position": { "x": 100, "y": 550 }
}
],
"edges": [
{ "id": "e1", "source": "0d1e2f3a-4b5c-4d6e-8f90-a1b2c3d4e5f6", "target": "1e2f3a4b-5c6d-4e7f-9a01-b2c3d4e5f6a7" },
{ "id": "e2", "source": "1e2f3a4b-5c6d-4e7f-9a01-b2c3d4e5f6a7", "target": "2f3a4b5c-6d7e-4f80-a112-c3d4e5f6a7b8" },
{ "id": "e3", "source": "2f3a4b5c-6d7e-4f80-a112-c3d4e5f6a7b8", "target": "3a4b5c6d-7e8f-4091-b223-d4e5f6a7b8c9" }
],
"weightPolicies": [
{
"id": "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a",
"name": "orders-critical-weight",
"description": "Critical alerts of orders weigh 100",
"filters": {
"operator": "AND",
"clauses": [
{ "key": "service", "op": "=", "value": "orders" },
{ "key": "severity", "op": "=", "value": "critical" }
]
},
"weight": 100,
"status": "active"
}
],
"catalogService": {
"serviceId": "orders",
"name": "Orders",
"description": "Order intake and fulfilment",
"icon": "fa:cart-shopping",
"alertImpact": { "severities": ["critical", "major"], "statuses": ["open"], "whitelist": { "operator": "AND", "clauses": [] }, "blacklist": { "operator": "AND", "clauses": [] } }
}
}
| Key | Content |
|---|---|
kind | tobealert-service-topology for one topology, tobealert-service-topology-bundle for a bundle |
schemaVersion | 2. Files with another version are rejected (unsupportedSchemaVersion) |
exportedAt / appVersion | When the file was produced and by which ToBeAlert version. Informational: the importer ignores them |
topology | The record: id, name, description, service, serviceKpi, orientation (TB, LR or CI). service is the identity used on import |
nodes / edges | The complete graph, exactly as the API returns it: stable IDs, kind, label, derived environment / resource, icon, params, hierarchyConfig and the canvas position |
weightPolicies | The weight policies that apply to the service: those tied to the topology plus the global ones whose Filters name the service (a clause on the service key). Each carries id, name, description, filters, weight, status |
catalogService | The entry of the Services catalog: serviceId, name, description, icon, alertImpact (severities, statuses, whitelist and blacklist). null when the service is not in the catalog |
A bundle wraps several files:
{
"kind": "tobealert-service-topology-bundle",
"schemaVersion": 2,
"exportedAt": "2026-10-09T10:42:00Z",
"appVersion": "1.12.0",
"topologies": [
{ "kind": "tobealert-service-topology", "schemaVersion": 2, "topology": { "service": "orders" }, "nodes": [], "edges": [], "weightPolicies": [], "catalogService": null },
{ "kind": "tobealert-service-topology", "schemaVersion": 2, "topology": { "service": "billing" }, "nodes": [], "edges": [], "weightPolicies": [], "catalogService": null }
]
}
The editor's Export to JSON (see Graph editor) writes only { "topology", "nodes", "edges" } from the canvas, unsaved changes included, and is meant for the editor's own Import from JSON mapping drawer. The export described here comes from the server and also carries weight policies and the catalog entry. The import dialog accepts both.
Import
Click Import in the header of the Services tab. The dialog walks through five steps:
| Step | What you do |
|---|---|
| Source | Choose a .json (or .csv for a CMDB) file, or paste the content |
| Format | The dialog detects the format: ToBeAlert export (single file, bundle, an editor export, or an export from an earlier release), CMDB (simple) (flat records — see Importing from a CMDB), or one of the third-party presets of the editor's Import from JSON drawer. Correct it if the detection is wrong |
| Mode | Replace or Merge (below). The dialog explains both; when the preview shows that something would be removed, it asks you to confirm |
| Preview | A dry run on the server: a table of counters per topology (nodes, edges, weight policies, catalog service) plus warnings. Nothing is written yet. Errors stop here |
| Import | Applies the import and shows the result |
A file with several topologies (a bundle) imports all of them in one go; the preview and the result list one row per topology. If any topology of the bundle is invalid, nothing is imported.
Which topology is updated
The importer matches on the service name in topology.service:
- A topology for that service exists → it is updated (its
idis kept, whatevertopology.idsays in the file). - No topology for that service → a new one is created, with the file's
name,description,orientationandserviceKpi. Creating counts against the Service Topology license limit like Create topology does.
Node IDs in the file are kept, so a topology re-imported from its own export keeps exactly the same IDs. When an ID already belongs to another topology on this instance (for example when you import a topology exported from a different service and renamed), that node gets a new ID, its edges follow, and the preview reports it (idsRegenerated).
Replace or merge
| Replace | Merge | |
|---|---|---|
| Intended for | Restoring a backup, promoting a topology from another instance, making the topology equal to the file | Adding nodes from a file to a topology you also edit by hand |
| Nodes in the file and in the topology | Updated: label, icon, parameters (such as the description), hierarchy configuration and position come from the file | Updated: label, icon, parameters and hierarchy configuration come from the file; the position on the canvas is kept (unless you choose to take positions from the file) |
| Nodes only in the file | Created | Created |
| Nodes only in the topology | Removed | Kept |
| Edges | Exactly the edges of the file; edges that are not in the file are removed | Edges of the file are added; no edge is removed |
| Weight policies | Policies of the file are created or updated by name and tied to the topology; policies tied to the topology that are not in the file are deleted | Policies of the file are created or updated by name and tied to the topology; nothing is deleted |
| Catalog service | Created if missing; otherwise description, icon and alertImpact are overwritten with the file's values | Created if missing; otherwise only empty fields are filled (an empty description, the default server icon, an alert impact without rules) |
| Result | The topology is the file | The topology is the union of both |
Nodes are matched by what they are, not by ID: the service node, an environment node by environment name, a resource node by environment + resource name. This is why a merge works even between topologies that were built independently.
After both modes, the graph is validated again as a whole and the resource graph is synchronized (relations with source topology, as after Save changes). A merge that would produce an invalid graph — typically a cycle, or the same resource reachable from two environments — is rejected with the usual error codes prefixed with after merge:; nothing is written.
In Replace mode, every node, edge and topology-tied weight policy that is not in the file disappears. The preview shows the remove counters before you confirm; take an export first if in doubt.
Preview
For each topology the preview shows:
| Counter | Meaning |
|---|---|
| Topology | create or update, and the ID of the existing topology |
| Nodes / Edges / Weight policies | How many will be created, updated, removed, or left unchanged |
| Catalog service | create, update (with the list of fields that change), unchanged, or skip when the file has no catalog entry |
| IDs regenerated | Node IDs that belonged to another topology and will be replaced |
and the warnings that apply:
| Warning | Meaning |
|---|---|
legacyConverted | The file was a tree from an earlier release and was converted to nodes and edges. The attached report says how many IDs were remapped, how many duplicate resources were merged into one node with several parents, and how many orphan nodes were dropped |
idsRegenerated | Some node IDs belonged to another topology and were regenerated |
positionsKept | Merge: the canvas positions of existing nodes were kept |
Files from earlier releases and other tools
| What you import | How it is handled |
|---|---|
Export from this release (kind: tobealert-service-topology) or a bundle | Imported as is |
Export to JSON from the graph editor ({ "topology", "nodes", "edges" }, no kind) | Imported as a topology without weight policies or catalog entry. If topology.service is missing, the dialog asks for the service |
Export from an earlier release (a nested tree with type and children, or { "service", "tree" }) | Converted to nodes and edges on the fly (legacyConverted). The service name comes from service, from the tree's service node, or from the one you type in the dialog |
| Third-party formats (Vue Flow, Cytoscape.js, D3, Datadog, Dynatrace, Elastic APM, AWS X-Ray, custom JSON) | Mapped to service / environment / resource nodes as in the editor's Import from JSON drawer, then imported like an editor export |
| Flat CMDB records (JSON or CSV) | See Importing from a CMDB |
Errors
The import is rejected as a whole — nothing is written — when the file cannot be read or any topology in it is invalid. The dialog lists each problem with its code and the path in the file:
| Code | Reason |
|---|---|
invalidJson | The content is not valid JSON |
invalidFormat | The JSON is none of the shapes above |
unsupportedSchemaVersion | schemaVersion is not 2 |
emptyBundle | A bundle with no topologies |
serviceMissing | No service name: the file has no topology.service, and none was typed |
invalidOrientation | topology.orientation is not TB, LR or CI |
tooLarge | The file is larger than 2 MB, or a topology has more than 5,000 nodes |
Any graph validation code (cycle, duplicateResource, resourceInMultipleEnvironments, serviceNodeCount, …) | The graph in the file — or, in merge mode, the merged graph (after merge: prefix) — breaks a rule |
Limits and permissions
| Item | Value |
|---|---|
| File size | 2 MB per import (a bundle counts as one file) |
| Nodes | 5,000 per topology |
| Export | Requires read:service_topologies |
| Import | Requires write:service_topologies; creating a topology also requires a free slot in the license limit |
| Audit trail | service-topology-exported per exported topology; service-topology-imported per topology created or updated (with the mode and the action) |
Best practices
- Export before a Replace import and before large restructuring in the editor; a bundle from Export all is a complete backup of every topology.
- Use Replace to promote a topology between instances (staging → production): the result is exactly the file, IDs included, so later re-imports stay idempotent.
- Use Merge to add nodes generated elsewhere to a topology people also draw by hand; positions and manual nodes survive. Remember that Merge never removes: to delete nodes, use the editor or a Replace import.
- Check the catalog step of the preview: in Replace mode the file overwrites the description, icon and alert impact of the service.
- Keep weight policy names unique: policies are matched by name across the whole instance, so a file that carries
production-critical-weightupdates the existing policy with that name and ties it to the imported topology. - For data that lives in a CMDB, prefer the CMDB import — it has no IDs or positions to maintain and can be re-run from a scheduled export.