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:
todbmlconnects 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.tosqltakes a DBML file and generatesCREATE TABLESQL, with the dialect determined by thedatabase_typesetting in the DBML file.todotgenerates a Graphviz DOT diagram from DBML, rendering tables with columns, types, primary/foreign key markers, and relationships connections.migratecompares two schemas (any combination of DBML files and live database connections) and outputs the SQL migration needed to go from one to the other.checkvalidates 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 TABLEcommands with engine-specific syntax likeAUTO_INCREMENT,SERIAL, orIF 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!