# How DrawDB Automatically Arranges Tables in Database Diagrams

> Discover how DrawDB automatically arranges database tables using the Dagre layout engine for optimal diagram clarity. Learn more about its intelligent positioning.

- Repository: [drawDB/drawdb](https://github.com/drawdb-io/drawdb)
- Tags: internals
- Published: 2026-08-14

---

**DrawDB uses the Dagre graph layout engine via the `autoArrange` utility in [`src/utils/autoArrange.js`](https://github.com/drawdb-io/drawdb/blob/main/src/utils/autoArrange.js) to compute optimal positions for tables based on their relational topology, locked status, and dynamic visual dimensions.**

When working with complex database schemas in DrawDB, manually positioning numerous tables becomes impractical. The open-source diagramming tool solves this through a sophisticated automatic layout system that analyzes entity relationships and visual constraints to produce clean, readable diagrams without manual intervention.

## The Auto-Arrange Algorithm Architecture

The core implementation resides in [`src/utils/autoArrange.js`](https://github.com/drawdb-io/drawdb/blob/main/src/utils/autoArrange.js), which exports a function that orchestrates a multi-stage layout pipeline. This utility receives three critical inputs: an array of table objects representing diagram entities, an array of relationship objects defining connections, and a settings object containing visual parameters like `tableWidth`, `showComments`, and separation distances.

### Preserving User Intent with Locked Tables

Before calculating positions, the algorithm respects manual adjustments by filtering out locked tables. Only entities with `!table.locked` are considered for repositioning, ensuring that deliberately placed tables remain stationary while the algorithm reorganizes surrounding elements.

```javascript
const movable = tables.filter((table) => !table.locked);

```

## Step-by-Step Layout Execution in [`src/utils/autoArrange.js`](https://github.com/drawdb-io/drawdb/blob/main/src/utils/autoArrange.js)

### 1. Connected Component Detection

The system first distinguishes between tables participating in relationships and isolated entities. It constructs a `connectedIds` set by iterating through the relationships array, identifying tables where both endpoints are movable. This separation allows the algorithm to apply graph-based layout to connected schemas while handling standalone tables separately.

### 2. Dynamic Size Calculation

Visual dimensions are computed using the `sizeOf` helper function (lines 24-32), which invokes `getTableHeight` from [`src/utils/utils.js`](https://github.com/drawdb-io/drawdb/blob/main/src/utils/utils.js). This calculation accounts for:
- Field count and heights defined in [`src/data/constants.js`](https://github.com/drawdb-io/drawdb/blob/main/src/data/constants.js)
- Comment visibility states (`showComments`)
- Header dimensions (`tableHeaderHeight`)
- Relationship indicator spacing

### 3. Graph Construction with Dagre

For connected tables, the algorithm builds a directed graph using the `@dagrejs/dagre` library. Each table becomes a node with pre-calculated dimensions, while relationships become directed edges. The graph configuration specifies left-to-right orientation:

```javascript
const graph = new dagre.graphlib.Graph();
graph.setGraph({ rankdir: "LR", ranksep: rankSep, nodesep: nodeSep });

```

### 4. Layout Computation

Dagre's `layout(graph)` method executes the actual positioning algorithm (line 54), computing optimal `x` and `y` coordinates that minimize edge crossings and respect the specified separation constraints. The algorithm then centers these coordinates on each node's top-left corner for proper alignment with DrawDB's coordinate system.

### 5. Isolated Table Grid Placement

Tables without relationships are arranged in a grid pattern beneath the connected component. The layout algorithm calculates row positions using the `isolatedGap` parameter and the overall width of the connected graph, preventing visual overlap while maintaining uniform spacing.

```javascript
// Simplified logic for isolated table placement
const positions = [];
let currentX = 0;
let currentY = connectedHeight + isolatedGap;

```

## Fallback Manual Layout

When users prefer simpler distributions or when the auto-arrange feature is bypassed, DrawDB falls back to [`src/utils/arrangeTables.js`](https://github.com/drawdb-io/drawdb/blob/main/src/utils/arrangeTables.js). This deterministic algorithm divides tables into two horizontal rows with fixed gaps, providing a quick organizational option that lacks the relationship awareness of the Dagre-based approach but executes faster for simple schemas.

## Practical Implementation Example

To programmatically trigger layout calculation within a component or custom script:

```javascript
import { autoArrange } from '@/utils/autoArrange';

// Assuming current diagram state
const { tables, relationships, settings } = diagram;

// Calculate new positions
const newPositions = autoArrange(tables, relationships, settings);

// Apply coordinates to state
newPositions.forEach(({ id, x, y }) => {
  const table = tables.find(t => t.id === id);
  if (table) {
    table.x = x;
    table.y = y;
  }
});

```

The function returns an array of `{ id, x, y }` objects that integrate directly with the diagram's state management, triggering a re-render with optimized positions.

## Summary

- DrawDB automatically arrange tables using the Dagre directed graph library implemented in [`src/utils/autoArrange.js`](https://github.com/drawdb-io/drawdb/blob/main/src/utils/autoArrange.js)
- The algorithm filters locked tables, calculates dynamic heights using constants from [`src/data/constants.js`](https://github.com/drawdb-io/drawdb/blob/main/src/data/constants.js), and builds a relational graph
- Connected components use hierarchical left-to-right layout while isolated tables utilize a grid placement algorithm
- Visual spacing is controlled via `nodeSep`, `rankSep`, and `isolatedGap` configuration parameters
- A deterministic fallback exists in [`src/utils/arrangeTables.js`](https://github.com/drawdb-io/drawdb/blob/main/src/utils/arrangeTables.js) for simple row-based arrangements

## Frequently Asked Questions

### What graph layout library does DrawDB use for auto-arranging tables?

DrawDB uses **Dagre** (`@dagrejs/dagre`), a directed graph layout engine specifically designed for DAGs (Directed Acyclic Graphs). Dagre computes optimal node positions while minimizing edge crossings and respecting user-defined separation constraints between ranks and nodes.

### How does DrawDB prevent manually positioned tables from moving during auto-arrangment?

The `autoArrange` function checks the `locked` boolean property on each table object at lines 12-22. Tables with `locked: true` are excluded from the `movable` array, ensuring they remain at their current coordinates while the algorithm repositions only unlocked tables around them.

### Can I customize the spacing between auto-arranged tables?

Yes, the algorithm respects three key spacing parameters passed through the settings object: `nodeSep` controls horizontal gaps between adjacent nodes, `rankSep` determines vertical distance between hierarchical levels, and `isolatedGap` sets the spacing for the grid layout applied to unconnected tables.

### What happens to tables that have no relationships to other entities?

Isolated tables are detected during the connected component analysis and routed to a separate layout path (lines 68-84). These tables are arranged in a simple grid pattern beneath the connected component, calculated using the `isolatedGap` parameter and the bounding width of the main graph to ensure visual balance.