Edges & Protocols
Edges represent the transport-layer connections between nodes. Understanding edge direction is the single most important concept for building correct cloud-arch diagrams.
The Edge Direction Rule
connect(A, B) means A opens the TCP connection to B.
The arrow direction answers the question: who dials whom? It does NOT indicate the direction of data flow. Once a TCP connection is established, data flows in both directions. Responses travel back along the same edge in reverse animation — you never need a duplicate edge for responses.
Think of it as asking: which process runs connect() or dial() at the OS socket level?
- Spark reads Postgres via JDBC → Spark calls
connect()→connect('spark', 'pg') - A Kafka consumer reads from a broker → Consumer calls
connect()→connect('flink', 'kafka') - Airflow submits a Spark job via the K8s API → Airflow calls
connect()→connect('airflow', 'spark')
Correct vs wrong examples
| Scenario | Correct | Wrong | Reason |
|---|---|---|---|
| Spark reads Postgres via JDBC | connect('spark', 'pg') | connect('pg', 'spark') | Spark opens the JDBC socket to Postgres |
| Airflow submits Spark job | connect('airflow', 'spark') | connect('spark', 'airflow') | Airflow calls the K8s/Spark API |
| Debezium reads WAL | connect('debezium', 'pg-primary') | connect('pg-primary', 'debezium') | Debezium opens the replication slot |
| Kafka consumer | connect('flink', 'kafka') | connect('kafka', 'flink') | Consumer connects to the broker |
| Trino queries Iceberg | connect('trino', 'iceberg') | connect('iceberg', 'trino') | Trino calls the Iceberg REST catalog API |
Responses do not need new edges
The FlowBuilder handles reverse animation automatically:
// ONE edge in the topology
topology.connect('client', 'api', { protocol: 'http', label: 'REST' });
// Animation: request goes forward, response goes backward on the SAME edge
flow
.from('client').to('api') // forward
.showMessage('[GET] /data')
.from('api').to('client') // REVERSE — no extra edge needed
.showMessage('[200 OK] Here is your data');Edge types
The type property in ConnectionOptions controls which React component renders the edge.
| Type | Component | Description |
|---|---|---|
floating | AnimatedFloatingEdge | Default. Smooth animated dashes. Works correctly with nodes inside groups. |
animated | AnimatedEdge | Simple animated dashes. Use for basic diagrams without group nesting. |
pulse | PulseEdge | Pulsing glow effect. Recommended for Kafka, RabbitMQ, and event-stream connections. |
topology.connect('producer', 'kafka', { type: 'pulse', protocol: 'kafka' });
topology.connect('api', 'db', { type: 'floating', protocol: 'postgresql' });Protocol color map
The protocol property controls the edge color. Use it to make connection types visually distinguishable at a glance.
| Protocol | Color | Typical use |
|---|---|---|
http | Blue | REST APIs, HTTP webhooks |
https | Blue | TLS-encrypted HTTP |
grpc | Indigo | gRPC service calls |
postgresql | Dark blue | PostgreSQL / JDBC |
mysql | Orange | MySQL |
redis | Red | Redis commands |
kafka | Orange-yellow | Kafka produce / consume |
rabbitmq | Orange | AMQP messages |
tcp | Gray | Raw TCP (unspecified protocol) |
udp | Light gray | UDP datagrams |
websocket | Teal | WebSocket connections |
amqp | Orange | Generic AMQP |
If no protocol is specified, the edge renders in the default gray.
Full edge options reference
topology.connect(source: string, target: string, options?: {
label?: string; // Text shown at the midpoint of the edge
protocol?: string; // Controls edge color
type?: 'floating' | 'animated' | 'pulse'; // Edge component
layer?: string; // Visibility layer
animated?: boolean; // Enable/disable dash animation (default: true)
bidirectional?: boolean; // Render arrowheads on both ends (default: false)
})Common mistakes
Mistake 1: Adding reverse edges for responses
// WRONG — creates two visible edges on the canvas
topology.connect('client', 'api', { protocol: 'http' });
topology.connect('api', 'client', { protocol: 'http' }); // redundant
// CORRECT — one edge, FlowBuilder handles reverse automatically
topology.connect('client', 'api', { protocol: 'http' });Mistake 2: Edge bypasses a proxy
// WRONG — client bypasses the circuit breaker in the response path
topology.connect('client', 'cb', { protocol: 'http' });
topology.connect('cb', 'service', { protocol: 'http' });
topology.connect('service', 'client', { protocol: 'http' }); // bypasses cb!
// CORRECT — responses go back through the circuit breaker
topology.connect('client', 'cb', { protocol: 'http' });
topology.connect('cb', 'service', { protocol: 'http' });
// Response path: service → cb (reverse) → client (reverse)Mistake 3: Wrong initiator direction
// WRONG — a Kafka broker does not dial consumers
topology.connect('kafka', 'flink', { protocol: 'kafka' });
// CORRECT — Flink consumers dial the Kafka broker
topology.connect('flink', 'kafka', { protocol: 'kafka' });