Generative AI works best when everything is plain text. Code, configuration, documentation, data, the more you can represent as readable text files, the more effectively an AI agent can reason about it and transform it. Database schemas are no exception. You can dump a schema as SQL DDL and hand it to your AI agent, and that works. But SQL DDL is imperative and verbose; it tells you how to create tables, not what the schema looks like. DBML (Database Markup Language) is the answer: a clean, declarative, database-agnostic language for defining schemas that both humans and AI can read and work with comfortably.

To fine-tune my AI workflow I wrote some DBML command-line tooling (dbml-tools) and that’s what this post is about.

What is DBML?

DBML (Database Markup Language) is an open-source DSL created by Holistics for defining database schemas. It is declarative rather than imperative: instead of CREATE TABLE statements with engine-specific syntax, you write concise table definitions with types, constraints, and relationships. Compare a typical SQL DDL dump with its DBML equivalent you’ll see it is shorter and easier to read.

DBML has a growing ecosystem with editor plugins, parsers in multiple languages, and visualization tools like dbdiagram.io. What I was missing was a Go-based CLI that could introspect a live database, produce valid DBML, and generate migration SQL in case of DBML changes. This way I can let an AI agent update the schema without worrying about validation or having to write migrations by hand.

What dbml-tools can do

My dbml-tools application is a toolset written in Go with five main commands:

  • todbml connects to a live MariaDB, PostgreSQL, or SQLite database and outputs its schema as DBML. Column types can be preserved as-is or normalized to database-agnostic equivalents with --normalize.
  • tosql takes a DBML file and generates CREATE TABLE SQL, with the dialect determined by the database_type setting in the DBML file.
  • todot generates a Graphviz DOT diagram from DBML, rendering tables with columns, types, primary/foreign key markers, and relationships connections.
  • migrate compares two schemas (any combination of DBML files and live database connections) and outputs the SQL migration needed to go from one to the other.
  • check validates a DBML file for syntax and semantic errors.

Why not just use SQL dumps?

A mysqldump --no-data or pg_dump --schema-only gives you a valid schema representation, and you can certainly hand that to an AI. But SQL DDL has drawbacks as a working format:

  • It is imperative: the output is a sequence of CREATE TABLE commands with engine-specific syntax like AUTO_INCREMENT, SERIAL, or IF NOT EXISTS.
  • It is vendor-locked: a MariaDB dump cannot be read by PostgreSQL without translation.
  • It is noisy: DDL includes storage parameters, character sets, collations, and other details that obscure the logical structure.

DBML gives you the logical schema in a clean, consistent format. The --normalize flag goes further by mapping vendor-specific types like character varying(255) to canonical equivalents like varchar(255), making the output truly database-agnostic.

Round-tripping and migrations

Because dbml-tools can both read from databases and generate SQL, you get a full round-trip. More importantly, the migrate command lets you diff any two schemas and get the exact SQL to migrate between them. Either argument can be a DBML file or a live database connection:

# Compare a DBML file against a live database
dbml-tools migrate postgres://user:pass@host/db schema.dbml

This means you can keep a schema.dbml file in your repository as the source of truth, let an AI edit it, and then generate the migration SQL to apply the changes to your database. DBML also supports comments on tables and columns, just like code comments. These explain why a table or column exists, not just what type it has. Those comments help an AI agent understand the design, not just the structure, and therefor improve its output.

A DBML toolchain in Go

I wrote dbml-tools from scratch in Go, including a full DBML lexer, parser, and interpreter. The tool has no external dependencies beyond database drivers. The introspection queries for MariaDB, PostgreSQL, and SQLite scan the tables, their columns, and the relations between them.

You can find the code on my GitHub:

https://github.com/mevdschee/dbml-tools

Enjoy!