TopologyBuilder
TopologyBuilder is the entry point for defining an architecture topology. It manages groups, standalone nodes, and edges, then commits everything to the React Flow store with a single apply() call.
const topology = new TopologyBuilder(autoLayout: boolean);| Parameter | Type | Description |
|---|---|---|
autoLayout | boolean | When true, node positions are computed automatically using a force-directed algorithm. When false, you must supply explicit x/y coordinates for every group. |
createGroup
Creates a group container and returns a GroupBuilder for adding nodes and sub-groups.
topology.createGroup(
id: string,
config: GroupConfig,
position?: { x: number; y: number }
): GroupBuilderGroupConfig
| Property | Type | Default | Description |
|---|---|---|---|
label | string | — | Display name shown in the group header |
width | number | 400 | Initial width in pixels (recalculated by autoResize) |
height | number | 200 | Initial height in pixels (recalculated by autoResize) |
style | object | {} | Inline CSS applied to the group container |
color | string | — | Border and header accent color (hex or CSS color) |
layer | string | — | Layer name; group is hidden when this layer is inactive |
Usage
const backendGroup = topology.createGroup('backend', {
label: 'Backend Services',
width: 700,
height: 300,
color: '#3b82f6',
layer: 'v2',
}, { x: 200, y: 300 });When autoLayout is true, the position argument is ignored. Pass it anyway for documentation purposes — it has no effect.
createProcess
Creates a standalone node (not inside any group) and adds it directly to the canvas.
topology.createProcess(config: ProcessConfig): TopologyBuilderProcessConfig
| Property | Type | Default | Description |
|---|---|---|---|
id | string | — | Required. Unique node identifier across the entire topology |
label | string | — | Required. Display name |
state | 'running' | 'stopped' | 'error' | 'warning' | 'running' | Visual state indicator |
shape | string | 'default' | Node shape. See Node Types & Shapes |
layer | string | — | Layer name for visibility toggling |
replicas | number | — | Shorthand: creates N nodes with IDs id-1 … id-N |
shardId | string | — | Shard identifier shown as a badge |
shardRole | 'primary' | 'replica' | 'arbiter' | — | Shard role badge |
external | boolean | false | Marks the node as external (orange border styling) |
Usage
topology.createProcess({
id: 'cdn',
label: 'CDN',
shape: 'cloud',
external: true,
state: 'running',
});connect
Creates a directed edge between two nodes.
topology.connect(
source: string,
target: string,
options?: ConnectionOptions
): TopologyBuilderconnect(A, B) means A opens the TCP connection to B. The arrow direction represents who dials whom, not who sends data. Responses always travel back along the same edge in reverse — never create a duplicate edge for responses.
ConnectionOptions
| Property | Type | Default | Description |
|---|---|---|---|
label | string | — | Text shown on the edge midpoint |
protocol | string | — | Connection protocol. Controls edge color. See Edges & Protocols |
type | 'floating' | 'animated' | 'pulse' | 'floating' | Edge component to render |
layer | string | — | Layer name for visibility toggling |
animated | boolean | true | Whether the edge animates (dashes move) |
bidirectional | boolean | false | Renders arrows on both ends |
Usage
topology.connect('api', 'pg', {
protocol: 'postgresql',
label: 'SQL queries',
type: 'floating',
});
topology.connect('flink', 'kafka', {
protocol: 'kafka',
label: 'consume',
type: 'pulse',
});apply
Commits all groups, nodes, and edges to the Zustand store. Triggers a React re-render and populates the canvas.
await topology.apply(): Promise<void>apply() is asynchronous because it waits for React Flow to finish its layout pass before resolving. Always await it.
await topology.apply();
// Canvas is populated here. Safe to create FlowBuilder.
const flow = new FlowBuilder();autoResizeGroups
Recalculates the dimensions of all groups to fit their contents. Equivalent to calling .autoResize() on every GroupBuilder after the fact.
topology.autoResizeGroups(): TopologyBuilderUseful when you add nodes to groups dynamically and want a single resize pass at the end.
// Build all groups and nodes...
topology.autoResizeGroups();
await topology.apply();newRow
Signals the auto-layout engine to place the next group on a new row, below the current row of groups.
topology.newRow(): TopologyBuildertopology.createGroup('row1-left', { label: 'Service A' });
topology.createGroup('row1-right', { label: 'Service B' });
topology.newRow();
topology.createGroup('row2', { label: 'Database Layer' });Other container and node factories
createGroup / createProcess cover most scripts. The builder also exposes typed
factories that set the right node type, default styling and nesting behaviour.
| Method | Signature | Produces |
|---|---|---|
createNode | createNode(id, type, position, data) | Escape hatch — any NodeType directly |
createClient | createClient(id, position, { label, description? }) | A client / browser node |
createActor | createActor(id, position, { label, description?, role? }) | A human actor |
createDatabase | createDatabase(id, position, { label, description? }) | A standalone database node |
createVM | createVM(id, position, data) | A VM container. Returns a VMBuilder |
createHost | createHost(id, position, data) | A physical host container. Returns a HostBuilder |
createCloud | createCloud(id, data, position?) | A cloud container. Returns a GroupBuilder |
createDataCenter | createDataCenter(id, position, data) | A datacenter container. Returns a DataCenterBuilder |
createDataCenterWithContents | createDataCenterWithContents(id, position, data) | Datacenter plus its children in one call |
createProcessInGroup | createProcessInGroup(id, groupId, position, data) | Process at an explicit position inside an existing group |
createProcessInGroupAuto | createProcessInGroupAuto(id, groupId, data) | Same, with the position auto-assigned |
Each factory returns a different fluent builder with a different set of add* methods —
see the builder family table.
Layout and presentation control
| Method | Signature | Effect |
|---|---|---|
collapseByDefault | collapseByDefault() | Groups render collapsed on first paint; the viewer can expand them |
forceNodePosition | forceNodePosition(id, { x, y }) | Overrides the auto-layout position for one node |
skipPosition | skipPosition(groupId) | Leaves a gap in the auto-layout sequence of that group |
addToGroup | addToGroup(childId, parentId) | Re-parents an existing node into a group — sets parentId and extent: 'parent'. This is what group.addGroup() calls under the hood; prefer addGroup() when creating nested groups |
Full example
const topology = new TopologyBuilder(true);
// External client (no group)
topology.createProcess({
id: 'internet',
label: 'Internet',
shape: 'cloud',
external: true,
});
// Frontend group
const frontendGroup = topology.createGroup('frontend', {
label: 'Frontend',
color: '#10b981',
});
frontendGroup
.addProcess({ id: 'nginx', label: 'Nginx', state: 'running' })
.addProcess({ id: 'spa', label: 'React SPA', state: 'running' })
.autoResize();
topology.newRow();
// Backend group
const backendGroup = topology.createGroup('backend', {
label: 'Backend',
color: '#3b82f6',
});
backendGroup
.addProcess({ id: 'api-1', label: 'API Pod 1', state: 'running' })
.addProcess({ id: 'api-2', label: 'API Pod 2', state: 'running' })
.addProcess({ id: 'pg', label: 'PostgreSQL', shape: 'cylinder', state: 'running' })
.autoResize();
// Connections
topology.connect('internet', 'nginx', { protocol: 'http', label: 'HTTPS' });
topology.connect('nginx', 'spa', { protocol: 'http', label: 'static' });
topology.connect('nginx', 'api-1', { protocol: 'http', label: 'proxy' });
topology.connect('nginx', 'api-2', { protocol: 'http', label: 'proxy' });
topology.connect('api-1', 'pg', { protocol: 'postgresql', label: 'SQL' });
topology.connect('api-2', 'pg', { protocol: 'postgresql', label: 'SQL' });
await topology.apply();
return null;