Search for data minimisation and you will find the same post many times over. Establish a lawful basis. Collect only what you need. Keep it only as long as you must. All correct, and all stopping at the exact moment the work gets hard. Knowing you should minimise is easy. Knowing which fields to minimise, inside a system that has been running for years, is the part nobody writes about.
The Step Everyone Skips
A principle tells you the goal. It does not tell you where to point. In a small, new codebase you can hold the whole data model in your head and reason about every field. That is not the system most of us maintain. The systems that carry real personal data have run for years, absorbed a dozen teams, and accumulated fields that no single person can still account for. You cannot minimise what you cannot see.
Why You Cannot Just Delete a Field
Try it in an old system. Pick a column, take it to a meeting, propose removing it. What happens next is always the same. Someone is not sure whether a downstream job reads it. Someone remembers a report that might depend on it. Someone raises a batch process from three years ago that no one has opened since. Nobody can prove the field is safe to remove, so it stays. Multiply that by every field captured out of habit and you have the real reason minimisation stalls. It is not disagreement with the principle. It is the absence of evidence.
Minimisation Is Two Problems, Not One
It helps to split them. The first is preventing over collection going forward, a design problem you solve with purpose mapping, review gates, and asking for a field only at the point you actually need it. The second is finding what you already collect and no longer use, a discovery problem. The first is well covered everywhere. This piece is about the second, because that is where programmes get stuck.
Read the Code, Do Not Poll the Room
When you ask a room which fields are unused, you are not measuring the system. You are sampling memory, and memory defends itself. Every field has an owner, and no owner volunteers to delete their own column, so uncertainty always resolves to keep it just in case. The code carries no such instinct. Whether a field is ever read by any path is not a matter of opinion. It is a property of the source, and it can be traced.
What the Scan Found
To make this concrete, I pointed Scrutora at Apache Fineract, a widely used open source core banking platform. It reads the repository, identifies the personal data fields, and traces where each one travels in the code.

The result is a flow map. Every tracked field on the left, every place it ends up on the right, and a ribbon for each path between them. The width of a ribbon reflects how many fields travel it and how far they go.

Then there is the other set. Grey ribbons that reach none of that.

The Shortlist You Can Act On
That grey set is the answer the meeting could never reach. A field whose only destination is at rest is a field the code never consumes. In Fineract, that set includes these, among others:
latitudelongitudenational_idhouse_phone_numberaddressLine2Defined, stored, and read by nothing. This is not a delete list yet. It is something more useful than a debate. It is a precise, named shortlist, produced from evidence, that turns the burden of proof around. Instead of asking a tired team to prove field by field that a column is needed, you put the exact set of fields that nothing in the code reads on the table and ask someone to justify keeping each one. Prove we still need this collapses far faster than prove we can safely remove this.
Two honest limits
At rest declared means the scan found no consumer inside this repository. A field can read as untouched in code and still feed a system outside the scan, so you confirm that before you drop a column.
And no code path reads it is not the same as the business does not need it. The scan hands you the shortlist and the evidence. The decision stays yours.
What You Actually Do With It
Finding the unused fields is the hard half. Here is how the rest of the work fits around it.
Confirm, then remove.
Take each field on the shortlist, check for any consumer outside the codebase, and where there is none, drop the column and stop collecting it.
Prevent the regrowth.
A shortlist you clear once grows back if collection is never gated. Every new field should name a documented purpose before it ships, and anything that cannot is not collected. Ask for a field at the point you need it, not by default at signup.
Minimise what you must keep.
For data you genuinely use, reduce its form and its life. Retention schedules with automated purge remove data once its purpose expires. Store a derived value instead of the raw one where you can, the age band rather than the date of birth, the city rather than the full address.
Complement the code with the logs.
Static analysis tells you which code paths exist. Runtime query and access logs tell you which ones actually ran. Reconciling the two catches the field that looks dead in code but is read once a year by a scheduled job.
Make it hold with ownership.
Every field gets an owner who periodically re-justifies it, and your record of processing gets reconciled against what the systems actually hold, not reviewed on paper.
The Principle Was Never the Problem
The gap was always evidence. Once you can see which fields the code actually reads, minimisation stops being a value you nod at in a policy and becomes a list you can work through on a Tuesday afternoon. Here is the full trace from the scan, every field to every destination, the red in motion and the grey at rest.
Every field you store is a promise you have to keep and a liability you have to defend. Fineract is holding 24 it never uses. Most production systems are holding far more, and have never once looked.
Vimalendukumar Dwivedi is Co-founder of Scrutora, a Code Compliance Platform.
Find your own shortlist
Scrutora traces every personal-data field in your codebase to wherever it actually lands, at rest or in motion, and hands you the evidence instead of another meeting.
Share this article