SfSkills Domains Docs GitHub

Home / admin / picklist-and-value-sets

picklist-and-value-sets

Use when creating or managing picklist fields: choosing between Global Value Sets and object-local picklists, configuring controlling and dependent field relationships, managing picklist values, and replacing values in existing data records.

Open the skill folder on GitHub


Picklist and Value Sets

Use this skill when an admin needs to create, configure, or manage picklist fields in a Salesforce org — including the decision between Global Value Sets and object-local picklists, setting up controlling and dependent relationships, and replacing stale values in data records.


Before Starting

Gather this context before working on anything in this area:


Questions to Ask Before Configuring

Ask these before opening Setup or writing a .globalValueSet-meta.xml. Each one maps to a documented platform behaviour that is expensive to discover after the deploy.

AskWhy it mattersWhat a good answer adds
"Does this exact value list already exist on another object, and is it a global value set or three copies?"Decides valueSetName vs valueSetDefinition. A field bound to a global set is restricted and its values can only be edited at the set (api_meta.txt:43704–43711)The one metadata file that owns the values, and the fields that inherit it
"Which of these values will code, reports, or an integration compare against by string?"fullName is the stored key; label is display. "Always use the value when inserting or updating a field. The query() call always returns the value, not the label" (object_reference.txt:2372–2374)A value naming decision made once, before rows exist, instead of a Replace job later
"Is the org's existing set going to be retrieved before I edit it?"Omitting a value from a deployed file deactivates it (api_meta.txt:47482–47483). A hand-authored file is a mass deactivationA retrieve-edit-deploy loop instead of a from-scratch file
"Is this a standard picklist, and if so which StandardValueSet name?"Standard picklists are StandardValueSet, the names differ from the field names, and the type takes no wildcard (api_meta.txt:130826–130828, Appendix C)The exact package.xml members, checked against Appendix C footnotes 2 and 3 for sets that cannot be inserted or read at all
"Does anything about this field depend on the value set staying open — a data load, a legacy integration?"Unrestricted picklists let the API mint values: "the system creates an 'inactive' picklist value" (object_reference.txt:2364–2366)An explicit restricted decision rather than the default drifting into a cleanup project
"Will any of these values be the dependent side of a controlling field?"A global-set-backed field can control but cannot be dependent, and matrix entries added via the API cannot be removed via the API (api_meta.txt:45855–45860)The dependency design settled before the field type is locked in — admin/field-dependency-and-controlling
"How many records already carry the values I am about to retire?"Deactivate keeps them, Delete nulls them with no undo, Replace runs a background jobA count per value from the SOQL in references/metadata-examples.md §9, and a Replace/Deactivate/Delete decision per value

What a proper configuration adds over just adding the values: the value set has one owner file, the stored API names are the ones code already compares against, retiring a value is a reversible isActive flip rather than a silent null-out, and the deploy is a diff against a retrieve instead of a file that deactivates whatever it forgot to mention.


Core Concepts

Global Value Sets vs Object-Local Picklists

A Global Value Set (metadata type GlobalValueSet) is a shared library of picklist values managed centrally under Setup > Picklist Value Sets. Multiple custom picklist fields across multiple objects can reference the same Global Value Set, so adding a value in one place adds it everywhere.

An object-local picklist is a value set defined within a single custom field. Its values are independent; changing them does not affect any other field.

Standard picklist fields (e.g. Lead.LeadSource, Opportunity.StageName) have their own built-in value management under Setup > Object Manager and cannot be converted to Global Value Sets. However, standard picklists CAN act as controlling fields for dependent custom picklists.

Key behavioral differences:

BehaviorGlobal Value SetObject-Local Picklist
Value scopeAll fields sharing the GVSThis field only
Add/remove valuesAt GVS level; affects all fieldsAt field level; isolated
Deactivate a valueDeactivates on all fields using GVSDeactivates on this field only
Promote to GVS laterNot possible once field is saved as localCan promote via UI (one-time, irreversible)
Metadata typeGlobalValueSetCustomField value set

Limits:

Controlling and Dependent Picklists

A controlling field determines which values are available in a dependent picklist. The user selects a value in the controlling field, and the dependent field automatically filters its available values to the mapped subset.

Supported controlling field types:

Not supported as controlling fields:

Supported dependent field types:

Not supported as dependent fields:

Dependency enforcement: Filtering is enforced in the Salesforce Lightning UI and Classic UI when a user creates or edits a record. Dependencies are NOT enforced via API, Data Loader, or record import. Records loaded through the API can have any value regardless of the dependency configuration. This is a known platform behavior, not a bug.

Configuration steps:

  1. Setup > Object Manager > [Object] > Fields & Relationships
  2. Click on the dependent field → Field Dependencies → Edit
  3. For each controlling value column, check the boxes for the dependent values that should be available
  4. Save — dependency is active immediately; no deployment needed in same org

Limit: A controlling picklist field may have at most 300 values. If a picklist exceeds 300 values it cannot be used as a controlling field. This limit can be raised via Salesforce Support. Large dependency matrices are difficult to maintain in the UI — prefer simpler value sets for controlling fields.

Zero-mapping gotcha: If no dependent values are checked for a given controlling value in the matrix, the dependent picklist shows all available values when that controlling value is selected — not zero values. This is the opposite of what most admins expect. Always confirm every controlling value has at least one mapped dependent value.

Picklist Value Management (Add, Retire, Replace)

Adding a value:

Deactivating (retiring) a value:

Replacing values in existing data (mass update):

Global Value Set: Promote an Existing Field

If a custom picklist field was created as object-local and you later decide the values should be shared, you can promote it to a Global Value Set:


Common Patterns

Pattern 1: Shared Industry/Region Values Across Multiple Objects

When to use: You have a "Region" picklist needed on Account, Opportunity, and Contact. Values must stay in sync — adding a new region should appear everywhere.

How it works:

  1. Setup > Picklist Value Sets > New → create Region__gvs with all region values
  2. Create each field as Type = Picklist → in the value set section, select "Use Global Value Set" → choose Region__gvs
  3. To add a new region: Setup > Picklist Value Sets > Region__gvs > Add value — it immediately appears on all three fields

Why not object-local: Managing separate value lists on three fields guarantees drift — one admin adds "Pacific Northwest" to Account but forgets Contact, causing report inconsistencies.

Pattern 2: Controlling Picklist — Product Category → Product Type

When to use: A "Product Category" picklist should filter the available "Product Type" values so that selecting "Hardware" shows only hardware types, not software types.

How it works:

  1. Create Product_Category__c (picklist) and Product_Type__c (picklist) on the object
  2. Add all category values to Product_Category__c
  3. Add all type values to Product_Type__c
  4. Object Manager > [Field] Product_Type__c > Field Dependencies > Edit
  5. In the matrix, for each Product_Category__c column, check the applicable Product_Type__c rows
  6. Save — filtering is live on the UI

Important: On the field dependency matrix, the "Include Values" button selects all values for a column; use it to start from "all" and deselect the few that don't apply, rather than checking hundreds of boxes manually.

Pattern 3: Retiring a Value Without Losing Historical Reporting

When to use: A picklist value is no longer valid (e.g. a product line was discontinued) but historical records must still show the value in reports.

How it works:

  1. Do NOT delete the value — deleting replaces it with null on all records
  2. Instead: Object Manager > [Field] > Edit → find the value → Deactivate it
  3. Existing records retain the value and it appears in reports; it is simply hidden from the selection UI for new/edited records
  4. If you want to rebrand the value (e.g. "Widget v1" → "Widget (Legacy)"), use Replace first to bulk-update all records, then deactivate the old label

Decision Guidance

SituationRecommended ApproachReason
Same values needed on 2+ objectsGlobal Value SetSingle source of truth; avoids value drift
Values are unique to one object/fieldObject-local picklistSimpler; no unintended cross-object impact
Field already exists as object-local, now needs sharingPromote to GVS (one-time)Preserves existing values; consolidates management
Retiring a picklist value, keep historyDeactivate the valueRecords keep value; UI hides from selection
Retiring a value, clean up old data tooReplace then DeactivateBulk-update records first, then deactivate
Need one field to filter another field's optionsControlling + Dependent picklistBuilt-in platform feature; no Apex needed
Values differ between orgs/sandboxesObject-local or GVS with changesetGVS is metadata and deploys via Changesets/SFDX

  1. Answer the seven questions above and record the answers in

    templates/picklist-and-value-sets-template.md. Sections 1 and 2 of that template are the Global-Value-Set-vs-local decision and the value list with API name, label and active flag.

  2. Count the data before deciding anything about existing values. Run the GROUP BY query in

    references/metadata-examples.md §9 per field. A value with rows is a Replace job; a value with zero rows is the only one safe to Delete.

  3. Retrieve, never author from scratch. `sf project retrieve start --metadata

    "GlobalValueSet:<Name>__gvs"(wildcard works) and eachStandardValueSet:<Name>` by name (no wildcard). Edit the retrieved file — a file missing values deactivates them on deploy.

  4. Write the metadata from references/metadata-examples.md: §1 global value set, §2 the field

    that consumes it, §3/§4 standard value sets, §5 translations, §6 the valueSettings shape (design the matrix in admin/field-dependency-and-controlling first), §7 package.xml.

  5. Lint — `python3 scripts/check_picklist_and_value_sets.py --manifest-dir

    force-app/main/default. It fails on duplicatefullNamein one set, more than onedefault,valueSetNamealongsidevalueSetDefinition, and anOpportunityStagevalue missingprobabilityorforecastCategory`; it warns on an unrestricted global-set-backed field.

  6. Dry-run then deploy (§8), and diff the dry-run output against the retrieve from step 3 —

    deactivations show up there, not in the file you wrote.

  7. Verify in the org, not in the deploy log — run the anonymous Apex in §9. getPicklistValues()

    returns only active values, so a deactivated value should be absent from the output. Re-run the GROUP BY from step 2 after any Replace job. Then walk the Review Checklist below.


Review Checklist

Run through these before marking picklist work complete:


Salesforce-Specific Gotchas

Non-obvious platform behaviors that cause real production problems:

  1. Deactivating a GVS value deactivates it everywhere — When you deactivate a value in a Global Value Set, it is hidden from the selection UI on every field that references that GVS, across all objects. There is no per-field deactivation for GVS values. Admins who expect to deactivate "On Hold" only on Cases — without affecting Opportunities that also use the same GVS — will be surprised.
  2. Dependent picklist dependencies are not enforced via API — Data Loader, REST API, SOAP API, Bulk API, Apex, and Flow (any write without UI interaction) all bypass the controlling/dependent relationship. Records can have any value regardless of the controlling field value. This means data imports and programmatic inserts can violate the intended dependency silently. Only the Lightning and Classic UIs enforce the filter, because the dependency filters which values the picklist offers rather than validating on save — so the access mode the write runs in is irrelevant. Do not expect the user-mode default that Apex database operations pick up at class apiVersion 67.0+ (Summer '26) — the gate is the .cls-meta.xml value, not the org's release — to close this: user mode enforces sharing, FLS, and object permissions, not picklist dependencies. See 2 § Apex security idiom by API version.
  3. Deleting a picklist value replaces it with null on all records — When you choose to delete (not deactivate) a picklist value, Salesforce immediately sets the field to null/blank on every record that had that value. This cannot be undone. Always use Deactivate or Replace first unless you intentionally want to blank out all records. For large orgs, even a Deactivate before Delete does not give you a rollback window.

Output Artifacts

ArtifactDescription
Picklist Design DocumentFilled template documenting value set choices, GVS vs local decision, dependent picklist matrix, and replacement plan
Data Replacement Job PlanList of Replace jobs to run, their order, and verification steps

Reference Files

FileRead it when
references/metadata-examples.mdWriting any GlobalValueSet, StandardValueSet, GlobalValueSetTranslation or picklist CustomField XML — plus the package.xml wildcard rules, retrieve/deploy commands, and the Apex + SOQL verification pair
references/gotchas.mdBefore deactivating, renaming, deleting or replacing any value, and before trusting a retrieved file to be complete
references/examples.mdWorking a concrete case end to end: a Replace across 12,000 records, consolidating three drifted fields into one global set, a country/state dependency
references/llm-anti-patterns.mdReviewing generated picklist metadata or generated advice about picklist values
references/well-architected.mdFraming global-vs-local and dependency-vs-validation-rule as a tradeoff, and for the source list
templates/picklist-and-value-sets-template.mdBefore creating or restructuring any value set worth reviewing — it is the artifact steps 1 and 2 of the workflow produce
scripts/check_picklist_and_value_sets.pyStep 5 of the workflow, and in CI on any branch that touches globalValueSets/, standardValueSets/ or a picklist field

Package files