Reverse engineer the whole database so nothing is missing, then let an AI agent that can read the application code sort the tables into domains, and review that grouping the way you would review any other change. The catalog knows every table and key; only the codebase knows which of them are billing, which are auth and which are a feature someone half-removed in 2019.
Anyone who has inherited a large undocumented schema knows the first diagram is a disappointment. Alexey Makhotkin’s essay on 240 tables and no documentation opens its advice bluntly: “forget about full-database graphical schemas: they are cluttered, they don’t really explain anything, and they are noisy with the implementation artifacts.” He also suggests managing expectations and setting a goal of “maybe about half” of the 240. The tools confirm the scale problem from the other side: in 2016 a user filed a MySQL bug because Workbench could not reverse engineer an ER diagram with 730 tables in one schema, and the fix, shipped in Workbench 6.3.9, was a warning above 1000 objects.
How to understand a legacy database with hundreds of tables
Work in two passes, because completeness and meaning come from different places.
The first pass is mechanical and should be total: reverse engineer the live database into an ERD so every table, column and key is in one model, and none of your later reasoning rests on a table you did not know existed. It is also the pass where missing foreign keys hurt most. A legacy schema often enforces its references in application code, so it opens as boxes with nothing between them; Schemity infers those relationships from column names such as customer_id and draws them dashed as virtual relations, which is the difference between a map and a grid when the database never declared its foreign keys.
The second pass is interpretive: which tables form one part of the system. That is where legacy documentation efforts usually stall, and it is worth understanding why the tools cannot do it for you.
Why can’t auto-layout group tables by domain?
Because the database does not contain the answer. An auto-layout reads what the catalog holds, which is tables, columns and keys, and arranges by that: connected tables drift together, isolated ones scatter, or everything is sorted by name. DbSchema’s own guide to reverse engineering MySQL diagrams describes the standard sequence honestly: run Auto Arrange, “which lays them out with a graph algorithm”, then right-click and choose New Group “to cluster the tables of one module into a named, colored group you can move as a unit”, one module at a time, by hand.
A foreign key graph is a poor proxy for a module. A users table is referenced by nearly everything, so it pulls every domain toward the middle; an audit log references nothing and lands at the edge regardless of what it audits; two tables in the same feature with no key between them never meet.
The module boundaries are real, though. They are simply written somewhere else. Django is the plainest example: its table naming rule joins the app label to the model name, so class Book in an app called bookstore becomes the table bookstore_book. Most codebases carry the same knowledge less literally, in the folders their models sit in, the services that write to a table and the names of the jobs that read it. That is the context an engineer spends weeks absorbing, and it is exactly the context a coding agent already reads.
| Sorting by hand | Graph auto-layout | AI agent reading the code | |
|---|---|---|---|
| Where the grouping comes from | Your memory and interviews | Foreign keys only | Models, folders and services in the repository |
| Knows the module boundaries | Eventually | No | From the code that defines them |
| Time on a few hundred tables | Days | Seconds | Minutes, plus your review |
| How you check the result | You are the check | Nothing to check | Step-by-step history you can undo |
Grouping a reverse engineered ERD with an AI agent
The run below is the whole workflow on a real legacy schema in under two minutes: the mechanical layout after connecting, the agent grouping it into domains, and the Context Map at the end.
1. Connect the agent to Schemity. Schemity runs a local MCP server, so Claude Code, Cursor or any other MCP host can read the diagram you have open and stage edits on it. Setting it up is one command in Claude Code, pointing at a server that listens only on your machine. The agent never receives database credentials: it reads the schema Schemity already holds.
2. Ask from inside the codebase. Open the agent in the repository that uses the database and ask for the grouping in plain terms, for example: group these entities into legends by domain, based on how the code organizes its models, and route the relations so the lines are readable. The agent reads the schema from Schemity and the modules from your code, then creates one legend per domain and runs relation routing, so lines go around tables and share corridors instead of crossing through them.
3. Review what it did. An agent’s grouping is a draft, and it will sometimes put a table in the wrong domain, usually a shared one like users or a table the code barely touches. Every change lands as an unsaved edit and appears in History with the name of the agent that made it, so a wrong grouping is one undo away and nothing is kept until you save. Legends are presentation: they never reach the database, which is what makes this safe to hand to an agent at all.
From domain legends to context views and the Context Map
Once the legends match the system, turn them into something you can work in. A context view is a focused sub-diagram showing a subset of the main ERD, which stays the single source of truth. Sync from legends in the Context Views drawer gives every legend a context view holding exactly its tables, in one click, so thirty domains become thirty readable diagrams without anyone dragging a table.
Then open the Context Map. Each context view becomes a single node, the arrows between them are counted from the foreign keys that cross each boundary, and the map arranges itself the first time you open it. This is the answer to the question a legacy codebase eventually raises: which modules depend on which, and where the cycles are. The agent can read the same dependencies over MCP, including indirect cycles across several contexts, and a curved arrow on the map marks two contexts that depend on each other.
Because the legacy database keeps changing underneath you, the diagram is only useful if it follows. Reopening a connected diagram re-syncs it against the live schema while every table keeps its position and its domain, so a new table appears ready to be placed rather than resetting the work.
What the agent does not replace
The agent replaces the sorting, not the understanding. Makhotkin’s advice to spend time talking to the people with local knowledge still stands, and the grouping gives those conversations a better starting point: a map with named domains to argue about instead of a wall of boxes to explain. Some of what they know is not in any diagram at all, such as which columns a trigger fills in rather than the application, which is why a trigger-maintained column is harder to spot than a generated one.
Nor does it replace the review of what the agent writes next: when the grouping turns into a migration, review the schema change the migration makes, not its SQL.
It also does not change the method, only its speed. The approach in you don’t need a diagram of all 800 tables is the same one: get everything into one model, then read it one subject area at a time. What changes is who draws the first version of the subject areas, and that the draft now comes from the code that actually defines them. For the privacy side of letting an agent near a client’s schema, AI help with your database design without a vendor cloud in the middle covers where the schema goes and what the agent can and cannot touch, and your DDD context map is already in your foreign keys goes deeper on reading the result.
Frequently asked questions
Can I generate an ER diagram from an existing database that has no foreign keys?
Yes, but most tools will draw the tables with no lines between them, because they read relationships only from declared foreign key constraints. Tools that can infer relationships from column naming, such as a user_id column pointing at a users table, recover most of the structure, and the inferred lines should be marked as undeclared so nobody mistakes them for enforced keys.
Does grouping tables into domains change the database?
No. Grouping is presentation: a legend or a sub-diagram records which tables belong together on the canvas and in the diagram file, and nothing about it is sent to the database. That is why it is safe to let an agent propose the grouping and to rearrange it as your understanding improves.
Should I document a legacy database all at once?
No. A diagram of every table is too dense to read, and practitioners who have done it recommend a realistic target of roughly half of a large schema at first. Get the whole schema into the tool so nothing is missing, then understand it one subject area at a time.