← All articles

GTM Engineering

Your 400 Custom Fields Are Debt an LLM Will Expose

Every custom field was a workaround for a question the CRM could not answer. An LLM answers those questions from the raw record. The fields are now debt, and the debt is coming due.

· 12 min read

I pulled the field usage report on an Opportunity object with 412 custom fields. 71 of them had a non-null value on more than a quarter of records. The rest were populated on a handful of rows, or on none. Every one of those 341 dead fields was created on purpose, by someone solving a real problem, in a meeting where adding a field felt like the answer. The field was never the answer. It was a workaround for a question the CRM could not answer on its own, frozen into schema and left there forever.

Here is the shift that turns those fields from harmless clutter into debt that is coming due. The reason you built a “Deal_Complexity__c” picklist was that no query could tell you how complex a deal was, so you made a human classify it into a field. An LLM reads the raw opportunity, the emails, the notes, the line items, and answers “how complex is this deal” on demand, from the source, without a field, without a human, and without the drift. The moment inference is cheap, a derived field stops being infrastructure and becomes a stale cache of a question you can now ask live. Stale caches are debt. This one has 341 rows.

412
Custom fields on one Opportunity object
17%
Populated on more than a quarter of records
6 of 47
Required fields reps actually fill honestly

Watch the object collapse before you read the argument. Four hundred and twelve custom fields dissolve to the 71 facts that carry weight, then to the handful still worth storing, and finally to a single generative layer that answers every question the other 341 fields were pretending to answer. The pile that vanishes is not lost information. It is cached answers a model now computes live.

From 412 stored fields to one generative layerThe fields dissolve into the few that are load-bearing
412All custom fieldsEvery field ever added in a meeting where a field felt like the answer.

Two kinds of fields, and only one is debt

Not every field is debt, so start by splitting them. There are fields that hold facts a human or system observed and cannot be re-derived: the amount, the close date, the signed contract URL, the product on the line item. Those are the source of truth. Delete them and you have lost information forever. Keep every one.

Then there are derived fields: values someone computed or classified from other fields to answer a question. Deal complexity, health score, “is this strategic,” segment when segment is really just a bucket of employee count and revenue, “engagement level,” priority tier. Every one of these is a cached answer to a question, and the cache goes stale the moment the underlying facts change and nobody re-runs the classification. These are the debt. An LLM re-derives them live, from the facts, every time you ask.

The three costs of a derived field nobody prices

A derived field looks free after it is created. It is not. It carries three costs that compound, and none of them show up on a report until an LLM makes the cheaper alternative obvious.

The first is the fill cost. A required derived field is a tax on every rep, every record, forever. The required-fields tax is real: reps face 47 required fields and honestly fill 6, so the other 41 get garbage that makes the field worse than empty. The second is the drift cost. A field classified as “high complexity” in March is still “high complexity” in July even though the deal simplified, because nobody re-runs the classification. The field lies quietly. The third is the schema cost. Every field is a thing to secure, document, migrate, and reason about; 400 fields is a data model no human holds in their head, so nobody dares delete any of it, and it grows.

Field population on a 412-field Opportunity object
A long tail of near-dead fields. Each was created to answer a question. The ones under 10% populated are pure debt: the cost is paid, the value is gone.
View as table
ItemValue
Core facts (amt, date)98%
Used derived fields34%
Rarely-filled fields8%
Effectively dead2%

The migration: from stored field to computed view

The move is to stop storing derived answers and start computing them. The derived field becomes a query or an inference that runs when someone asks, over the facts, so it is never stale and never a fill tax. Here is the shape, drawn.

The inversion Facts stay stored, answers become computed
Core factsamount, dates,line items, docsread bySemantic layerSQL for deterministicLLM for judgmentcomputed on demandComplexityHealth, tier
The core facts remain the source of truth. Derived fields collapse into a semantic layer that computes answers on demand: SQL for deterministic ones, an LLM for the ones that used to need a human to classify.

Some derived fields collapse into plain SQL, because they were deterministic all along and someone just stored the answer to save a join. Segment is the classic one: it is almost always a function of employee count and revenue that got frozen into a picklist reps now edit by hand.

-- "Segment" was never a fact. It is a function of two facts.
-- Compute it in a view; stop storing and maintaining a field.
SELECT
  id,
  CASE
    WHEN employees >= 1000 OR annual_revenue >= 100000000 THEN 'Enterprise'
    WHEN employees >= 100  OR annual_revenue >= 10000000  THEN 'Mid-Market'
    ELSE 'SMB'
  END AS segment
FROM account;

The moment segment is a view, it cannot drift, cannot be fat-fingered, and costs a rep nothing. Every account that crosses 1,000 employees is Enterprise the instant the fact updates, with no field to re-classify. That is one field retired and one source of drift eliminated, from a five-line view.

The judgment fields, the ones that needed a human to read something, become an inference call instead of a stored value. Deal complexity was a picklist a rep set from a gut read; now it is a function of the facts.

{
  "field_retired": "Deal_Complexity__c",
  "computed_from": ["line_item_count", "product_mix", "legal_redlines", "stakeholder_count", "custom_terms_flag"],
  "method": "llm_classify",
  "output": { "complexity": "high", "confidence": 0.82,
              "reason": "9 line items across 3 product families, 2 rounds of legal redlines, non-standard payment terms." },
  "recompute": "on_demand"
}

The difference that matters: the reason field. A stored picklist tells you “high” and nothing about why or when. The computed version tells you why, from the current facts, every time you read it. It never lies, because it is never cached.

Not everything should be inferred

The counter-discipline matters, or you replace stale fields with expensive hallucinations. Deterministic derivations belong in SQL, not an LLM: segment, days-in-stage, coverage ratio, anything that is arithmetic on facts. Reach for inference only where the answer genuinely required reading unstructured content a human would have had to read. And a fact never becomes an inference: you do not “infer” the contract amount, you store it, because it is ground truth and getting it wrong is unforgivable.

The sort is not a matter of taste; each field has a right home and a real per-read cost. Deterministic derivations run for effectively zero in a view. Judgment fields cost a model call, and a call is cheap enough that the math almost never favors storing the answer. A Claygent research run in Clay costs about 1 to 6 credits depending on depth (Clay pricing, 2026), and a credit starts around 5 cents, so a classification lands in the low single-digit cents. Set that against the rep-minutes a required picklist burns on every record forever and the stored field loses on cost, not only on freshness.

Derived fieldWhat it really isRight homePer-read cost
SegmentEmployee count crossed a thresholdSQL view (CASE)~0, deterministic
Days in stageArithmetic on two timestampsSQL view~0, deterministic
Coverage ratioPipeline divided by quotaSQL view~0, deterministic
Deal complexityA human read the deal and judgedLLM classifycents per call (Clay, 2026)
Health / riskA human read usage and signalsLLM classifycents per call
”Is this strategic”A human read context and judgedLLM classifycents per call

The comparison that ends the argument

Stored derived field versus computed answer. Same question, two implementations.

Stored derived field Computed answer
Freshness Stale the moment facts change Recomputed from facts on read
Fill cost A rep enters it on every record Zero: nobody fills it
Drift Silent, unmeasured, permanent Impossible, there is nothing to drift
Auditability "High." No why, no when Reason and confidence, every read
Schema weight One more field to secure and migrate One line in a view or one prompt
Cost Rep minutes, hidden, recurring Cents of compute, visible, on demand
The stored field looked cheaper because its costs are hidden in rep time and quiet drift. The computed answer pays a small compute cost and eliminates every hidden one.

The migration math

A 412-field object does not shrink by deleting fields on a Friday. It shrinks by classifying, then computing, then deprecating in order. Here is the split I find and what happens to each pile.

PileCountDisposition
Core facts71Keep. Source of truth, cannot re-derive.
Deterministic derived~90Move to SQL views. Retire the field.
Judgment derived~60Move to on-demand inference. Retire the field.
Dead or near-dead~190Deprecate and delete after a usage-report grace period.

That is roughly 340 fields headed for retirement against 71 that stay, which matches the population report at the top: only the facts were ever carrying weight. The rest was cached answers and abandoned experiments.

The platforms are already leaning this way, even if they will not say it in these words. Salesforce is pushing Agentforce as a consumption layer that reads records and answers questions on the fly rather than demanding a field for every attribute, and HubSpot shipped Breeze AI credits (HubSpot, 2025) to do inference over the CRM instead of storing more of it. Both moves point at the same conclusion the field audit reaches from the other side: the value moved from what you store to what you can compute over what you store. The vendors monetizing inference are betting the derived-field pile shrinks, and they are the ones who watched a billion of these fields get created.

Here’s how I’d build it: the field-debt paydown

Do not big-bang this. You will break a report someone depends on and lose the room. Pay the debt down field by field, cheapest and highest-drift first, with a proof at each step.

The field-debt paydown
  1. 1

    Pull the field population report

    For every custom field, get percent populated and last-modified distribution. This is your debt ledger. Anything under 10% populated is a candidate for deletion, not migration.

  2. 2

    Sort every field into fact, deterministic, or judgment

    Facts stay. Deterministic derivations go to SQL. Judgment fields go to inference. This sort is the whole strategy; do it before you write any code.

  3. 3

    Collapse the easy deterministic fields into views

    Start with segment, tier, days-in-stage: anything that is arithmetic on facts. Ship the view, prove it matches the field on live data, then deprecate the field. One win the whole team can see.

  4. 4

    Replace one judgment field with on-demand inference

    Pick the highest-drift judgment field, deal complexity or health, and compute it from facts with a reason and confidence attached. Run it in shadow mode against the stored field first to earn trust.

  5. 5

    Deprecate on a grace period, never delete cold

    Rename the field, watch the usage report for anything still reading it, and delete only after a clean window. A field with zero reads for a quarter is safe to remove. This protects the report you did not know existed.

The shadow-mode discipline here is the same one I use for shadow-mode scoring: compute the new answer alongside the old field, compare, and only cut over when they agree or when the new one is demonstrably better. You do not earn the right to delete a field by arguing. You earn it by showing the computed answer was right and the stored one had drifted.

The 400 fields were never the problem. They were the best answer available when the CRM could not answer questions on its own. It can now, and the debt comes due the day someone points an LLM at your raw records and asks the questions your fields were pretending to answer. Get ahead of that day with one report this week: pull field population, sort the piles, and collapse your first deterministic field, segment is the easy one, into a five-line view. That single retired field is the proof you need to earn the next fifty.

crm-architecture ai data-model

Keep reading

One email. Every week.

One email a week: a system I built or broke, with the config, the numbers, and what I would change. No roundups, no theory, unsubscribe whenever it stops being useful.

The newsletter opens soon.

Connect a provider in src/config.ts