Not verified hands-on. This article was written from primary documentation rather than reproduced in an org, so it carries no tested-release badge. If you run it and something differs, say so in the comments and it gets tested and corrected.

The answer, briefly: deactivating a value hides it from the dropdown and leaves it on every record that already has it. Deleting asks you whether to replace it, and the replacement runs as a background job that rewrites your data. Neither one fixes the report filters, validation rules and Apex string comparisons that reference the old value by name, and those are what actually break.

The three operations, precisely

Deactivate. The value moves out of the active list. Users cannot select it going forward. Records holding it keep holding it, and the value still appears in reports, list views and exports. You can reactivate it later. This is the reversible option and it should be your default.

Delete with replacement. Salesforce asks which value to substitute and then updates every record holding the old one. It is a mass update, it takes time proportional to the record count, and it fires nothing you can hook into. It also does not run your validation rules, which is helpful here and confusing elsewhere.

Delete without replacement. The value leaves the list. Existing records keep the stored string, which is now not a member of the picklist. The record displays it, reports group by it, and the next time anyone edits that record the field has no valid selection. This is how orgs end up with picklists that report on values nobody can find in Setup.

Rename. Changing the label is display-only and is usually safe. Changing the API name is a different operation entirely: it changes the stored value, and everything matching on the string breaks at once.

What references a picklist value by name

More than you think. Work through this list before touching anything:

  • Validation rules and formulas using ISPICKVAL or TEXT() comparisons.
  • Report filters that stored the value when the report was saved. A filter on a deleted value silently returns nothing rather than erroring.
  • List view filters, same behaviour, and nobody checks list views.
  • Flows: decision elements, assignment values, and choice sets that hard-code the value.
  • Apex, wherever a string literal is compared to the field. The compiler will not help you.
  • Dependent picklists. Changing a controlling value rewires the dependency matrix, and controlled values can end up with no valid parent.
  • Record type assignments. A value available to one record type and not another, with the availability set per record type.
  • Integrations. Any external system sending that string on an insert or upsert. An inactive value sent by an API call is rejected on a restricted picklist and accepted on an unrestricted one, which is a meaningfully different outcome.

Retrieve the metadata and search it rather than clicking through Setup:

sf project retrieve start --metadata ApexClass,Flow,ValidationRule,Report,ListView
grep -rl "Awaiting Approval" force-app/

Restricted versus unrestricted

A restricted picklist rejects any value not in the list, including from the API and from a data load. An unrestricted one accepts anything and quietly adds it as an inactive value. Most older orgs have unrestricted picklists full of values created by a data load in 2018.

The order that avoids surprises

  1. Count the records. SELECT Status__c, COUNT(Id) FROM Case GROUP BY Status__c tells you what is actually in use, which is frequently not what the picklist contains.
  2. Search the metadata for the value string and fix every reference to use the new value, keeping both accepted for now.
  3. Add the new value and make it available to the right record types.
  4. Migrate the data yourself, with a data load, rather than using delete-with-replacement. You control the batching, you get a success file, and you can do it in stages.
  5. Deactivate the old value. Do not delete it.
  6. Wait a release. Then delete, if you still want to.

Doing your own migration instead of the replacement job matters when the mapping is not one-to-one. Replacement only does many-to-one. Splitting one old value into two new ones based on another field is a data load, always.

What will not update

Field history keeps the old strings forever. So do audit records, Chatter posts that quoted the value, and anything already exported.

Frequently asked

Can I undo a deletion? Deleted values can be restored for a limited period from the field’s detail page, which shows a list of deleted values. The replacement job that rewrote your records is not undone by restoring the value.

Does deactivating break a validation rule that references the value? No. The rule still evaluates, and it still matches records that hold the value. That is often exactly what you want during a transition.

What happens to a record whose value was deleted without replacement? It keeps the string. Editing the record in the UI usually forces a new selection before saving.