Pain points · English

A renamed column, and no list of what breaks

A renamed column breaks the reports and jobs that still use the old name. What you can list before you merge, and what no catalog will list for you.

Published

The column has been wrong for a year. orders.customer_id stores an account id, and every new hire trips on it. Someone renames it to orders.account_id in PostgreSQL, updates the application, and merges on Thursday. The migration succeeds. The app starts. The person who renamed the column goes to lunch.

The nightly job still says customer_id. So does a Metabase question finance runs on Monday, a notebook a teammate saved in March, and a view in the reporting schema that nobody remembered because it lives in a different repository. Each one fails on its own schedule. The first page arrives Friday night. The second arrives when finance opens the question. There is no list of them. There is a memory, and the memory was incomplete.

The worry is not the rename. The worry is the unknown reach of it. Reports, jobs, and other teams were reading the old name. Teams describe the workaround as a standing job: before you change a column, walk the building. That job does not scale, and it does not survive the person who holds the map leaving.

What a database will and will not tell you

The database knows the column's name, type, and the foreign keys that were declared. After the migration it knows the new name. It does not know about the question saved in a BI tool, the script in a cron on a box somebody else administers, or the spreadsheet that has the old name in a header because it was exported in June. Those consumers are outside the catalog.

Declared foreign keys help for consumers inside the same database, and only if people actually declared them. A string copy of the id in another system is invisible. An ORM that selects * and then reads a property by name fails in the application, not in the migration. The migration's success is a statement about the database. It is not a statement about everyone who had the old name written down.

So the fear is rational. A renamed or dropped column does not stay inside one table. The blast radius is the set of readers, and that set is not a query you can run against one catalog unless you have already collected the readers into one place. Most teams have not.

Why the usual tools stop at the current shape

A SQL client is good at the current shape of one connection. You can list columns, and you can see that customer_id is gone. You cannot ask it who still selects the old name, because those selects are not in this database. Open a second client for the reporting server and you have a second current shape. You still do not have the notebook.

A BI tool knows the questions saved inside it. That is a real list, and it is worth exporting before you merge. It is a list of that tool. The job in the other scheduler, the dbt model in another repo, and the partner query someone runs by hand are absent. Teams get hurt when they treat the BI dependency list as the whole list.

An export to Excel freezes the old header. It does not break when the column is renamed. It breaks later, when someone refreshes it, or it never breaks and keeps publishing the old extract. Silence is not safety. The file has left the system that would have errored.

A text-to-SQL chat pointed at one database learns the new name the next time it reads the catalog. That protects the next chat. It does nothing for the saved SQL that already contains the old name, and it does not produce the list of those statements. Asking the chat "what will this rename break?" gets you a guess from whatever context you pasted in. A guess is not a list you can trust.

The tools show you the schema they are connected to, at the moment you look. Impact is a question about other systems at other times. Those are different questions.

A list you write is better than a list you imagine

Search before you rename. Search the application repo, the transformations repo, the scheduler, and the BI tool's question list. Include the old name in quotes. Write down what you found, including the places you could not search. An incomplete list on a page is something the next person can extend. A feeling that you checked is not.

Prefer expand, then contract, when the column is read by anything you do not fully control. Add account_id, write both, move the readers you found, then drop customer_id in a later migration. A single-step rename is the version with the widest blast, because every missed reader fails at once. Two steps cost a migration. They also give you a week when both names work.

Put the old name in the migration message and in the pull request. The next failure will be searched by someone who was not in the review. They will search for customer_id. If that string exists only in the deleted line of a diff, they may not find the change.

If the list is thin and the column is on the path of a nightly job, do the change when a person can watch the job. Thursday night is a choice. It is a worse choice when you already know the list is incomplete.

A data contract is a different piece of work. It is a written promise about a column — name, type, meaning, who is allowed to change it — and a check that fails when a change breaks the promise. Browsing a catalog does not enforce that promise, and it does not compute the upstream and downstream graph for you. If you want the contract, write the promise and run the check. Do not expect a schema browser to have done it quietly.

Where DataTug fits

DataTug shows the current schema in the web app, the CLI and terminal UI, and AI chat, for the sources the project opens. The ones marked as working today are SQLite, PostgreSQL, MySQL, Oracle, SQL Server, BigQuery, inGitDB, and REST APIs. Tables and columns from those sources sit in one project, so the name you are about to change is something you can look up without opening a different client per engine.

That is the part the product shows. It is not an impact list, and it is not a data contract. DataTug does not enforce contracts, and it does not compute who is upstream or downstream of a column. After you look up customer_id in the project, the search across repos and the expand-then-contract migration are still yours.

When the schema you need to inspect is one of those sources, open it in datatug.app or from the CLI. Personal and public projects are free. Use the project as the place you look. Keep the list of readers in the pull request, where a schema browser cannot put it.

Pain pointsNext: Two exports, one number, and a weekly match by hand