diagrams-js
diagrams-js/svg-serialization
coreSVG export and import for diagrams. Render diagrams to SVG with embedded metadata for round-trip serialization. Import previously exported SVG images back into editable diagrams. Alternative to JSON serialization with self-contained visual + data format.
This skill builds on diagrams-js/getting-started and diagrams-js/provider-nodes. Read them first for foundational concepts.
diagrams-js — SVG Serialization
Export diagrams to SVG format with embedded metadata and import them back. SVG serves as both a visual image and a self-contained data format, enabling round-trip editing without separate JSON files.
Setup
import { Diagram } from "diagrams-js";
import { EC2 } from "diagrams-js/aws/compute";
const diagram = Diagram("My Architecture");
diagram.add(EC2("Server"));
// Render to SVG (includes embedded metadata by default)
const svg = await diagram.render();Core Patterns
Export to SVG
const diagram = Diagram("Web Architecture", {
direction: "TB",
theme: "pastel",
});
const web = diagram.add(EC2("Web Server"));
const db = diagram.add(RDS("Database"));
web.to(db);
// Render to SVG with embedded metadata
const svg = await diagram.render();
// Or use the explicit SVG exporter
const svg2 = await diagram.export("svg");
// Save to file
await diagram.save("architecture.svg");Import from SVG
Restore a diagram from an SVG string using the static Diagram.fromSVG() method:
import { Diagram } from "diagrams-js";
const svg = await fs.readFile("diagram.svg", "utf8");
// Restore the full diagram with all nodes, edges, and options
const diagram = await Diagram.fromSVG(svg);
const restoredSvg = await diagram.render();Merge SVG into Existing Diagram
Import an SVG into an existing diagram via the plugin system:
const diagram = Diagram("Merged Architecture");
await diagram.import(svgString, "svg");SVG Data Attributes
The embedded metadata includes:
- data-diagram-json (root <svg>): Base64-encoded full diagram JSON
- data-diagram-version: Format version for compatibility
- data-node-id, data-node-label: Per-node identifiers
- data-node-provider, data-node-type, data-node-resource: Provider metadata
- data-node-metadata: Base64-encoded custom metadata
- data-cluster-label, data-cluster-nodes: Cluster information
- data-edge-from, data-edge-to, data-edge-label: Edge information
These attributes enable DOM querying and third-party tooling.
Custom Classes and Data Attributes
Nodes, edges, and clusters can have custom CSS classes and data attributes injected into the SVG:
const server = diagram.add(
Node("Server", {
className: "highlight",
dataAttrs: { team: "backend", env: "prod" },
}),
);
web.to(
Edge({
className: "critical",
dataAttrs: { latency: "50ms" },
}),
db,
);
const cluster = diagram.cluster("VPC", {
className: "production",
dataAttrs: { region: "us-east-1" },
});Injected SVG output:
<g class="node highlight" data-node-id="Server" data-team="backend" data-env="prod">...</g>
<g
id="diagram_edge_0"
class="edge critical"
data-edge-from="web"
data-edge-to="db"
data-latency="50ms"
>...</g
>
<g class="cluster production" data-cluster-label="VPC" data-region="us-east-1">...</g>Access elements after rendering with getElement():
const svg = await diagram.render();
document.body.innerHTML = svg;
server.getElement()?.addEventListener("click", handler);
edge.getElement()?.classList.add("hovered");
cluster.getElement()?.setAttribute("data-active", "true");Clean SVG Without Metadata
To generate an SVG without embedded data:
const cleanSvg = await diagram.render({ embedData: false });This is useful when:
- Distributing diagrams to external parties
- Embedding in contexts where smaller file size matters
- Publishing to documentation where metadata is unnecessary
Round-trip Consistency
SVG serialization preserves all diagram data:
const original = Diagram("Test", { direction: "TB", theme: "blues" });
original.add(EC2("Server", { nodeId: "srv" }));
original.cluster("VPC").add(EC2("Web"));
// Export as SVG
const svg = await original.render();
// Import back
const restored = await Diagram.fromSVG(svg);
// Verify equivalence
const json1 = original.toJSON();
const json2 = restored.toJSON();
// json1 === json2Comparison: JSON vs SVG Serialization
| Feature | JSON | SVG |
|---|---|---|
| Human-readable | Yes | Partial (markup) |
| Visual preview | No | Yes (it's the image) |
| File size | Small | Larger (contains image) |
| DOM queryable | No | Yes (data attributes) |
| Round-trip | Yes | Yes |
| Best for | Version control, APIs | Distribution, documentation |
Common Mistakes
CRITICAL Trying to import plain SVG without embedded data
Wrong:
const plainSvg = `<svg xmlns="http://www.w3.org/2000/svg"><text>Hello</text></svg>`;
const diagram = await Diagram.fromSVG(plainSvg);
// Throws: Invalid diagram SVG: missing or corrupted embedded diagram dataCorrect:
// Only SVGs exported/rendered by diagrams-js can be imported
const svg = await diagram.render();
const restored = await Diagram.fromSVG(svg);Source: source code - svg.ts extractDiagramData validation
HIGH Assuming embedData defaults to false
Wrong:
const svg = await diagram.render();
// Surprised that SVG contains visible data attributes?
// embedData defaults to trueCorrect:
// Default behavior: embed metadata
const svg = await diagram.render(); // Contains data-diagram-json
// Opt-out when needed
const clean = await diagram.render({ embedData: false });Source: source code - Diagram.ts render() embedData check
MEDIUM Using diagram.export("svg") expecting different output from render()
Wrong:
const rendered = await diagram.render();
const exported = await diagram.export("svg");
// These are identical; export just calls render({ format: "svg" })Correct:
// Both produce the same SVG with embedded metadata
const svg = await diagram.render();
// Use render() directly; export is a convenience for plugin consistencySource: source code - svg.ts exporter implementation
See also
- diagrams-js/json-serialization — JSON export/import guide
- diagrams-js/rendering-export — Output formats and rendering options
- diagrams-js/diagrams-js-plugin-system — Plugin architecture