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. NOT for why the API or an integration ignores a dependency matrix - use admin/field-dependency-and-controlling. NOT for cleaning up degraded, unrestricted or orphaned picklist values - use admin/picklist-field-integrity-issues. NOT for record type picklis...
Installs into .claude/skills of the current project.
Are you the author of Picklist And Value Sets?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/pranavnagrecha-picklist-and-value-sets)
---
name: picklist-and-value-sets
description: "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. NOT for why the API or an integration ignores a dependency matrix - use admin/field-dependency-and-controlling. NOT for cleaning up degraded, unrestricted or orphaned picklist values - use admin/picklist-field-integrity-issues. NOT for record type picklist filtering - use admin/record-types-and-page-layouts. Keywords: GlobalValueSet, StandardValueSet, __gvs suffix, customValue, valueSetName, valueSetDefinition, restricted picklist, GlobalValueSetTranslation, OpportunityStage, CaseStatus."
category: admin
salesforce-version: "Spring '25+"
well-architected-pillars:
- Operational Excellence
- Reliability
tags:
- picklist
- global-value-set
- dependent-picklist
- controlling-field
- picklist-values
triggers:
- "how do I create a global picklist value set that multiple objects share"
- "my picklist is showing wrong values or old values I retired"
- "how do I set up a dependent picklist where one field controls another"
- "I need to replace an old picklist value with a new one across all existing records"
- "what is the difference between a global value set and an object-local picklist"
- "picklist value none is not blank"
- "silent default none on picklist"
- "how do I deactivate a picklist value without losing historical data"
- "users can still see deactivated picklist values on old records"
- "we have hundreds of picklist values and reps keep typing random ones"
- "picklist sprawl picklist value cleanup picklist governance"
- "data quality issues on picklist field with too many values"
- "consolidate or rationalize picklist values across objects"
- "duplicate or near-duplicate picklist values cluttering reports"
- "dependent picklist controlling field setup"
- "deploy a global value set and the values I left out got deactivated"
- "retrieve picklist values but only the active ones come back"
- "standardvalueset wildcard in package.xml returns nothing"
- "add a new opportunity stage with probability and forecast category"
- "case status closed flag not marking cases closed"
- "remove a value from the dependent picklist matrix via metadata api"
- "global value set __gvs suffix deploy error invalid fullname"
- "translate global picklist values into another language"
inputs:
- "Object and field names for the picklist field(s) involved"
- "Whether values need to be shared across multiple objects or are object-specific"
- "Whether a controlling/dependent relationship is needed and which field is the controller"
- "List of values to add, retire, replace, or reorder"
outputs:
- "Decision recommendation: Global Value Set vs object-local picklist"
- "Step-by-step configuration guide for the picklist or dependent picklist relationship"
- "Data replacement plan for existing records when renaming/retiring values"
- "Picklist design document using the provided template"
dependencies: []
version: 1.1.0
author: Pranav Nagrecha
updated: 2026-09-04
---
# 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:
- **Where is the field used?** Is the same set of values needed on more than one object? If yes, a Global Value Set is appropriate.
- **Is there a controlling/dependent requirement?** Which field controls which? Is the controlling field a standard picklist, custom picklist, or checkbox?
- **How many existing records carry the old value?** Mass replacement via Setup creates a background job — plan for data volume.
- **Are there dependent flows, validation rules, or Apex logic** that check specific picklist values by string? These must be updated when renaming or retiring values.
---
## 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.
| Ask | Why it matters | What 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 deactivation | A 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 job | A 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:**
| Behavior | Global Value Set | Object-Local Picklist |
|---|---|---|
| Value scope | All fields sharing the GVS | This field only |
| Add/remove values | At GVS level; affects all fields | At field level; isolated |
| Deactivate a value | Deactivates on all fields using GVS | Deactivates on this field only |
| Promote to GVS later | Not possible once field is saved as local | Can promote via UI (one-time, irreversible) |
| Metadata type | `GlobalValueSet` | `CustomField` value set |
**Limits:**
- Standard and custom picklists: up to **1,000 total values** (active + inactive combined); each value label has a max of **255 characters**; total characters across all values in a field is capped at **15,000**
- Multi-select picklists: **500 values** is both the default and the absolute maximum — new and existing orgs default to 500, an org sitting below it can be raised to 500 by Salesforce Support, and 500 cannot be exceeded. Separately, **at most 100 values can be selected at once** on a single record, and that 100 cannot be increased. (150 is a retired default that persists in older documentation and in model memory.)
- Global Value Sets: max **500 Global Value Sets per org**; same 1,000 value limit applies per GVS; GVS fields are **always restricted** (API writes of arbitrary text fail with `INVALID_OR_NULL_FOR_RESTRICTED_PICKLIST`)
### 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:**
- Standard picklist fields (e.g. `LeadSource`, `Type`)
- Custom picklist fields (standard or global-value-set backed)
- Checkbox fields (controls a dependent picklist with two branches: checked/unchecked)
**Not supported as controlling fields:**
- Multi-select picklists cannot be controlling fields
- Formula fields, lookup fields, text fields — not supported
- Certain Activity standard fields (Call Type, Subject, Task Type) cannot be controlling fields
**Supported dependent field types:**
- Custom picklist fields (object-local value set)
- Custom multi-select picklist fields
**Not supported as dependent fields:**
- Standard picklist fields — standard picklists cannot be on the dependent side
- Fields backed by a Global Value Set — GVS-backed fields can be **controlling** but **cannot be dependent**
**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:**
- Object Manager > [Object] > [Field] > Edit > Add picklist values
- Or for a Global Value Set: Setup > Picklist Value Sets > [GVS Name] > Edit
**Deactivating (retiring) a value:**
- Deactivated values remain on existing records and appear in reports — they just cannot be selected on new or edited records
- Records carrying a deactivated value still display it (labeled as inactive in some views)
- For Global Value Sets: deactivation applies across **all** fields sharing that GVS
**Replacing values in existing data (mass update):**
- Setup > Object Manager > [Object] > Fields & Relationships > [Field] > **Replace**
- Choose the old value and the replacement value (or blank to clear)
- Salesforce creates a background job to update all records — completion time scales with record volume
- You can replace with a blank/null value (effectively clearing the field on old records)
- **This does not apply to records in the Recycle Bin** — deleted records retain their original value
- After replacement, the old value remains in the field's value list as inactive unless you explicitly deactivate or delete it
### 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:
- Object Manager > [Object] > [Field] > Edit → there is a "Promote to Global Value Set" option if the field is custom
- This is **one-way and irreversible** — once promoted, the field's values are managed at the GVS level
- The values are not duplicated — existing values become the initial GVS values
- All other fields wanting to share these values must be created or modified to reference the new GVS
---
## 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
| Situation | Recommended Approach | Reason |
|---|---|---|
| Same values needed on 2+ objects | Global Value Set | Single source of truth; avoids value drift |
| Values are unique to one object/field | Object-local picklist | Simpler; no unintended cross-object impact |
| Field already exists as object-local, now needs sharing | Promote to GVS (one-time) | Preserves existing values; consolidates management |
| Retiring a picklist value, keep history | Deactivate the value | Records keep value; UI hides from selection |
| Retiring a value, clean up old data too | Replace then Deactivate | Bulk-update records first, then deactivate |
| Need one field to filter another field's options | Controlling + Dependent picklist | Built-in platform feature; no Apex needed |
| Values differ between orgs/sandboxes | Object-local or GVS with changeset | GVS is metadata and deploys via Changesets/SFDX |
---
## Recommended Workflow
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 each `StandardValueSet:<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 duplicate `fullName` in one set, more than one `default`,
`valueSetName` alongside `valueSetDefinition`, and an `OpportunityStage` value missing
`probability` or `forecastCategory`; 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:
- [ ] Global Value Set chosen for any value set used on 2+ fields/objects
- [ ] All values entered correctly (label matches API value intent; no trailing spaces)
- [ ] Inactive/deleted values checked — no data cleanup gap (use Replace if needed)
- [ ] For dependent picklists: dependency matrix is complete and tested in UI
- [ ] Downstream impacts verified: validation rules, flows, Apex (ISPICKVAL), reports, dashboards
- [ ] If Global Value Set: confirm deactivation of a value won't break other objects unexpectedly
- [ ] Replace job completed and verified on sample records before marking work done
- [ ] Field-Level Security (FLS) confirmed on new fields for all relevant profiles/permission sets
---
## 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 [`agents/_shared/AGENT_CONTRACT.md`](../../../agents/_shared/AGENT_CONTRACT.md) § *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
| Artifact | Description |
|---|---|
| Picklist Design Document | Filled template documenting value set choices, GVS vs local decision, dependent picklist matrix, and replacement plan |
| Data Replacement Job Plan | List of Replace jobs to run, their order, and verification steps |
---
## Reference Files
| File | Read it when |
|---|---|
| `references/metadata-examples.md` | Writing 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.md` | Before deactivating, renaming, deleting or replacing any value, and before trusting a retrieved file to be complete |
| `references/examples.md` | Working 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.md` | Reviewing generated picklist metadata or generated advice about picklist values |
| `references/well-architected.md` | Framing global-vs-local and dependency-vs-validation-rule as a tradeoff, and for the source list |
| `templates/picklist-and-value-sets-template.md` | Before 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.py` | Step 5 of the workflow, and in CI on any branch that touches `globalValueSets/`, `standardValueSets/` or a picklist field |
---
## Related Skills
- `admin/custom-field-creation` — use when the field itself needs to be created (type selection, FLS, layout); this skill handles picklist-specific design and value management
- `admin/field-dependency-and-controlling` — use for the dependency matrix design itself: which controlling value maps to which dependent value, checkbox controllers, LWC combobox behaviour, and why the API ignores the matrix. This skill owns only the `valueSettings` XML shape
- `admin/record-types-and-page-layouts` — use when record type determines which picklist values a user sees (per-record-type picklist value filtering is configured on the Record Type, not the field dependency)
- `admin/picklist-data-integrity` — use for the value-deactivation runbook and picklist governance across an existing estate
- `admin/picklist-field-integrity-issues` — use when invalid or orphaned values already exist in the data and need auditing and cleanup
- `admin/formula-fields` — use when a field's value is computed from a picklist using `ISPICKVAL()` or `TEXT()`