How DrawDB Parses and Imports DBML Files: A Complete Technical Guide

DrawDB parses DBML files using the @dbmljs/parser library to generate an AST, then transforms the parsed structure into internal diagram objects via the fromDBML(src, database) utility in src/utils/importFrom/dbml.js.

DrawDB is an open-source database design tool that treats DBML (Database Markup Language) as a first-class citizen for schema representation. The application converts plain-text DBML definitions into interactive diagrams through a dedicated import pipeline that maps AST nodes to internal models.

Overview of the DBML Import Architecture

The DBML import functionality is encapsulated in a pure utility module that isolates parsing logic from the UI layer. The src/utils/importFrom/dbml.js file exports the fromDBML function, which coordinates transformation between external DBML syntax and DrawDB's internal diagram representation.

The parsing pipeline follows these stages:

  1. Tokenization – Raw DBML text is parsed by the @dbmljs/parser library into a structured AST.
  2. Model instantiation – AST nodes are converted to Table, Column, Enum, and Relationship objects.
  3. Reference resolution – Foreign key targets and enum values are linked to their respective owners.
  4. State integration – Parsed objects are merged into the current database object passed to the function.

Deep Dive into the Parsing Logic

Tokenization and AST Generation

The fromDBML function delegates initial parsing to the @dbmljs/parser library. When invoked with a raw DBML string and the current database state, the function calls the parser's parse(src) method to generate an AST describing tables, enums, relationships, and notes.

This AST serves as an intermediate representation that captures the hierarchical structure of the DBML schema without coupling to DrawDB's internal model.

Transforming Tables and Columns

For each table node in the AST, the code creates a new Table instance and sets its name property. The function then iterates over the table's columns array to instantiate Column objects with the following attributes:

  • Data type – Extracted from the column definition.
  • Constraints – Primary key ([pk]), foreign key ([ref]), nullability, and default values.
  • Annotations – Inline comments and notes attached to specific columns.

The column mapping preserves DBML constraint syntax while translating it into DrawDB's internal validation flags.

Handling Enums and Relationships

Enum definitions undergo similar transformation. Each enum node becomes an Enum object, with individual entries converted to EnumValue instances. This preserves the enumerated type constraints for databases that support them.

Relationship parsing handles ref blocks by resolving source and target table-column identifiers. The parser determines cardinality from arrow direction (<, >, -, <>) and stores custom names or comments attached to the relationship definition.

Resolving References and Annotations

The final parsing stage resolves symbolic references between objects. Foreign key targets are linked to their corresponding table and column objects, while enum values are attached to columns that reference them. Stray comments and table-level notes are preserved and attached to their respective model elements.

The function returns a plain JavaScript structure mirroring the internal diagram representation, ready for immediate integration with the current database state.

Exporting DBML from DrawDB

While the import pipeline focuses on parsing, understanding the symmetrical toDBML(diagram) function in src/utils/exportAs/dbml.js provides context for the format's round-trip fidelity. This serializer walks the internal model and emits DBML syntax for tables, enums, and relationships, preserving order, comments, and cardinality annotations.

The export utility generates:

  • Table blocks with column definitions and constraints.
  • Enum declarations with value lists.
  • Ref lines expressing cardinality through arrow notation.
  • Inline comments derived from model annotations.

UI Integration Points

The parsing utilities remain pure functions without direct UI dependencies. Two React components orchestrate the user-facing workflow:

ImportDiagram.jsx (src/components/EditorHeader/Modal/ImportDiagram.jsx) handles file loading and invokes fromDBML when users import DBML files through the interface.

DBMLEditor.jsx (src/components/EditorSidePanel/DBMLEditor.jsx) displays generated DBML and triggers toDBML for real-time export or side-panel preview.

Practical Implementation Examples

Importing a DBML String into the Diagram

import { fromDBML } from '@/utils/importFrom/dbml';
import { useDiagram } from '@/hooks/useDiagram';

const rawDbml = `
Table users {
  id int [pk, increment]
  name varchar
  email varchar [unique, note: 'User contact address']
}

Table posts {
  id int [pk]
  user_id int [ref: > users.id]
  title varchar
}
`;

const { diagram, setDiagram } = useDiagram();

// Parse DBML into internal model
const parsed = fromDBML(rawDbml, diagram.database);

// Merge parsed objects into current diagram state
setDiagram(prev => ({
  ...prev,
  ...parsed,  // Contains tables, enums, relationships
}));

Exporting the Current Diagram as DBML

import { toDBML } from '@/utils/exportAs/dbml';
import { useDiagram } from '@/hooks/useDiagram';

const { diagram } = useDiagram();

// Serialize diagram to DBML format
const dbmlString = toDBML(diagram);

// Trigger file download
const blob = new Blob([dbmlString], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'schema.dbml';
a.click();

Summary

  • Primary parser: DrawDB relies on the @dbmljs/parser library to handle tokenization and AST generation from raw DBML text.
  • Import location: The fromDBML(src, database) function in src/utils/importFrom/dbml.js orchestrates the conversion pipeline.
  • Object mapping: AST nodes transform into Table, Column, Enum, and Relationship instances with resolved references.
  • UI separation: Pure utility functions ensure parsing logic remains decoupled from React components like ImportDiagram.jsx and DBMLEditor.jsx.
  • Bidirectional support: The complementary toDBML(diagram) export function ensures lossless round-tripping between formats.

Frequently Asked Questions

What parser library does DrawDB use for DBML files?

DrawDB uses the @dbmljs/parser library to parse DBML text. This library tokenizes the input and generates an AST that represents tables, columns, enums, relationships, and notes as structured nodes, which the fromDBML function then traverses to build internal objects.

How does DrawDB handle foreign key relationships during import?

The parser resolves ref blocks by identifying source and target table-column identifiers from the AST. It determines cardinality by analyzing arrow direction (<, >, -, or <>) in the DBML syntax, then creates Relationship objects that link the appropriate columns in the internal model.

Can DrawDB export diagrams back to DBML format?

Yes. The toDBML(diagram) function in src/utils/exportAs/dbml.js serializes the internal diagram model back to DBML syntax. It emits Table and Enum blocks, preserves constraint annotations like [pk] and [ref: > table.id], and maintains relationship cardinality through proper arrow notation.

Where is the DBML import logic located in the DrawDB source code?

The core import logic resides in src/utils/importFrom/dbml.js. UI components that trigger this logic include src/components/EditorHeader/Modal/ImportDiagram.jsx for file imports and src/components/EditorSidePanel/DBMLEditor.jsx for real-time DBML preview and export.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →