Custom Metadata Types & Custom Settings — Salesforce Admin 6
By this point in the admin journey, you have worked through org health, user experience, automation, approvals, and email. Each of those areas depends on decisions that may change over time: which feature is enabled, which queue owns work, what threshold applies, which template is used, or which integration endpoint an org should call. When those decisions are buried inside Flow conditions, formulas, validation rules, or Apex, small changes become harder to review and riskier to deploy.
Part 6 is about treating configuration as a first class asset. You will learn when to use Custom Metadata Types versus Custom Settings, how each behaves across deployments and environments, and how to model ownership, naming, documentation, and change control so the org stays predictable as it grows.
🧬 Custom Metadata Types & Custom Settings
Section titled “🧬 Custom Metadata Types & Custom Settings”Custom Metadata Types and Custom Settings can look similar at first, but they serve different operational purposes.
Custom Metadata Types define the schema for configuration that you store as Custom Metadata records. Both the type definition and its records are treated as metadata, so they can be deployed, versioned with your codebase, and promoted across environments in a controlled release process. They are a strong fit when configuration should move with deployments, such as feature flags, routing maps, or environment aware integration settings.
Custom Settings define configuration structures whose values are stored as org data records. In practice, this means the setting definition is metadata, while the stored values behave like data in the org. They are optimised for runtime access and straightforward admin updates, especially when values may change more frequently without a deployment. They are useful for lightweight defaults and user-level overrides that teams need to adjust operationally.
⚙️ When to Use Custom Metadata vs Custom Settings
Section titled “⚙️ When to Use Custom Metadata vs Custom Settings”Both custom metadata types and custom settings can hold org configuration, but they differ in how definitions and values are treated:
| Feature | Custom Metadata Types | Custom Settings |
|---|---|---|
| Definition (type) | Metadata | Metadata |
| Stored values (records) | Metadata records | Data records in the org |
| Deployment model | Type and records can move via metadata deployment/package workflows | Type can deploy as metadata; values are typically managed as org data |
| Versioning | Type + records fit source control and release pipelines well | Type is versionable; record values are more environment specific and harder to version cleanly |
| Runtime behaviour | Optimised for read access; ordinary Apex DML is not supported, but admins and metadata tooling can manage records | Optimised for read/write runtime access patterns (for example via Apex) |
| Use Case | Config you version with code (feature flags, org defaults, lookup tables) | User customisable settings, org-wide defaults |
| Scaling | Deployment-friendly configuration; org allocations still apply | Cached configuration data; org allocations still apply |
| Admin Updates | Setup or a metadata deployment, depending on governance | Setup or runtime data tooling |
When to use Custom Metadata:
- Feature flags (enable/disable features per org)
- Non-secret routing, mapping, and feature configuration that should move with a release
- Approval routing rules (route expense requests by department)
- Lookup tables (country codes, picklist mappings)
When to use Custom Settings:
- Org-wide defaults (default email sender, max records per batch)
- User-level preferences (debug logging per user, notification preferences)
- Settings that change frequently without code deploy
🛠️ Custom Metadata Types: Setup & Governance
Section titled “🛠️ Custom Metadata Types: Setup & Governance”Let’s build a practical custom metadata type: a feature flag registry that controls which features are enabled in each environment.
-
Create the Custom Metadata Type
- Setup → Custom Code → Custom Metadata Types
- Click New Custom Metadata Type
- Label:
Feature Flag - Plural Label:
Feature Flags - Object Name:
FeatureFlag - Description: “Controls feature availability across environments”
- Select: All Apex code and APIs can use the type, and it’s visible in Setup
- Save
-
Add Custom Fields
- Field 1:
Is_Enabled__c(Checkbox) - Field 2:
Description__c(Text, 255 characters) - Field 3:
Owner_Email__c(Email)
- Field 1:
-
Create Records
- In the Custom Metadata Type detail page and click Manage Feature Flags
- Click New to create a record
- Label:
New LWC Component - Feature Flag Name:
NEW_LWC_COMPONENT- Is_Enabled: ☑ (checked)
- Description: “New Lightning Web Component for opportunity dashboard”
- Owner_Email: [email protected]
- Click New again to create another record
- Label:
Beta Approval Flow - Feature Flag Name:
BETA_APPROVAL_FLOW- Is_Enabled: ☐ (unchecked)
- Description: “New approval process using orchestration (in beta)”
- Owner_Email: [email protected]
-
Deploy & Version
- Include the type and intended records in your change set or package
- Review each target org’s values as part of the release. If environments need different values, document how your pipeline or post-deployment step supplies them; an
Environment__cfield does not identify the current org by itself
Governance for Custom Metadata:
- Use names that communicate intent immediately: A good Custom Metadata Type name tells readers what decision space it controls (for example, feature flags, routing, or environment behaviour). Clear names reduce setup mistakes and make metadata easier to find during incident response.
- Adopt a consistent record-key pattern: Choose one record naming style and keep it consistent (for example, upper snake case such as
FINANCE_ROUTINGandENGINEERING_ROUTING). Consistent keys are easier to reference in formulas, Flow conditions, and deployment reviews. - Document ownership and purpose on each record: Include a concise description of what the record controls and who owns it. This prevents “mystery metadata” and makes change approvals faster.
- Run periodic hygiene reviews: Review metadata records on a regular cadence to remove deprecated entries, confirm owners are still valid, and ensure values still match current process design.
Take a look at the Custom Metadata Types Basics to continue your learning.
📝 Custom Settings: Organization-Wide and User-Level
Section titled “📝 Custom Settings: Organization-Wide and User-Level”Custom Settings are simpler operationally than Custom Metadata as the stored setting values (records) are org data. They come in two flavors:
- List (legacy choice for new designs): Named, org-wide configuration records. Salesforce disables the creation of new List custom setting types by default
- Hierarchy: Org-wide + user level overrides (users can override org defaults). This is the primary modern use case for Custom Settings.
Hierarchy custom settings let you define values that vary by organisation, profile, or user. Salesforce automatically resolves the most specific match (user > profile > org default), making them perfect for per-team feature flags, user specific thresholds, or profile based exceptions. List custom settings, by contrast, store org-wide lookup data that applies equally to everyone, like country codes, API endpoints, or configuration mappings, think shared reference tables rather than user specific overrides. Use hierarchy when behaviour changes by context (getInstance() auto-resolves), list when you need static org-wide records accessed by name.
Example: Org-Wide Custom Setting for Email Configuration
-
Create the Custom Setting
- Setup → Custom Code → Custom Settings
- Click New
- Label:
Email Configuration - Plural Label:
Email Configurations - Setting Type: List
- Visibility: Public
-
Add Fields
Default_Sender_Email__c(Text, 255 chars)Max_Email_Recipients__c(Number)Enable_Bounce_Tracking__c(Checkbox)
-
Create Org-Wide Record
- Click Manage Email Configurations
- Click New
- Record:
- Name:
Default - Default_Sender_Email: [email protected]
- Max_Email_Recipients: 100
- Enable_Bounce_Tracking: ☑
- Name:
-
Access in Apex
Email_Configuration__c emailConfig = Email_Configuration__c.getInstance('Default');String senderEmail = emailConfig.Default_Sender_Email__c;
For Hierarchy custom settings (user-specific overrides):
- Set Hierarchy as the Setting Type
- Create an org-wide record (for all users)
- Have an administrator create profile- or user-specific records where an override is genuinely needed
- Access in Apex:
Email_Configuration__c.getInstance(userId)
🔄 Using Custom Metadata & Settings for System Configuration
Section titled “🔄 Using Custom Metadata & Settings for System Configuration”Real World Case Study: Department Based Approval Routing
Imagine your org needs to route expense approvals by department:
- Finance department: route to Finance Manager
- Engineering: route to Engineering Lead
- Sales: route to VP of Sales
Instead of hardcoding routing logic, store it in custom metadata:
Custom Metadata Type: Approval_Routing__mdt
| DeveloperName | Department__c | Approver_Role__c | Escalation_Role__c |
|---|---|---|---|
| FINANCE_ROUTING | Finance | Finance Manager | CFO |
| ENGINEERING_ROUTING | Engineering | Engineering Lead | VP Engineering |
| SALES_ROUTING | Sales | Sales Manager | VP Sales |
In your Flow or Apex, query this metadata:
List<Approval_Routing__mdt> routingRules = [ SELECT DeveloperName, Department__c, Approver_Role__c, Escalation_Role__c FROM Approval_Routing__mdt WHERE Department__c = :expenseRecord.Department__c];Now, adding a new department takes seconds: create a new metadata record, deploy, and routing works automatically. No Apex changes needed.
Maintenance Pattern:
- Create one metadata record per department
- Review quarterly: retire departments that no longer exist
- Add notes to each record (owner email, effective date)
- Version all changes: track in source control or changeset history
Continue to learn how to use Custom Metadata programatically with the Programmatic Development with Custom Metadata Types trailhead module.
📦 Deploying Custom Metadata & Settings
Section titled “📦 Deploying Custom Metadata & Settings”Custom metadata is code like (definition + records are deployable as metadata); custom settings are data like (records live per org and are usually moved with data tools).
Custom Metadata Deployment
Section titled “Custom Metadata Deployment”Deploy custom metadata via:
- Change Sets: Setup → Outbound Change Sets → add the custom metadata type and its records → deploy
- Packages: Include the type and records in managed/unmanaged packages so they move with your app
- Metadata API / CLI: Use Salesforce CLI, Ant, or other metadata tooling to retrieve and deploy XML
Deployment Gotcha: Custom metadata records can’t be changed through ordinary Apex DML. Updates go through metadata changes (change sets, packages, Metadata API) or the Setup UI. Treat the record’s DeveloperName as a stable key: a rename requires you to update and deploy every Apex, Flow, formula, or configuration reference that uses it.
Custom Settings Deployment
Section titled “Custom Settings Deployment”Custom settings records behave like data, so you typically move them separately from their definition:
- Data Loader / data tools: Export from source org and insert into target org using the API
- Deployment tools: Use products like Gearset/BOFC or custom scripts to migrate custom setting data alongside other config
- Manual UI entry: Setup → Custom Settings → Manage → New/Edit for small numbers of records
- Apex / scripts: Seed records in test/migration code when you need repeatable initial data
Change sets and packages move the custom setting definition (fields, type), but not the data itself. If you deploy a bad value, there’s no built-in versioning—you roll back by restoring prior data via another load or script.
🚨 Limits, Gotchas & Troubleshooting
Section titled “🚨 Limits, Gotchas & Troubleshooting”Salesforce enforces a few important limits around custom metadata and custom settings that are easy to bump into in real projects:
- Custom metadata usage: The org has allocations for custom metadata types, fields, and total record size. Check the current Custom Metadata Type Usage page and Salesforce limits for the target org rather than designing around a copied number.
- Custom settings usage: Custom settings count against platform allocations and their cached data allowance depends partly on licensing. Check the target org’s current limits before using a setting for a large lookup table.
- Query behaviour: Apex queries for custom metadata records are generally exempt from the standard SOQL query and row limits, although queries containing long text area fields are an exception. Flow queries for custom metadata count towards the transaction’s limits. Review Salesforce’s Custom Metadata Type limitations before using a Get Records element repeatedly in bulk automation.
- Record size: Custom metadata usage is affected by the size of the fields you define, so large text fields are a poor fit for bulky content.
Common Gotchas
Section titled “Common Gotchas”- Runtime caching: Custom settings and custom metadata are cached for fast read access. Changes made via Setup or deployments are visible to new transactions, but long running Apex or integrations won’t see updated values mid transaction. Don’t rely on “hot swapping” configuration during critical batch runs.
- Deployment order: If Custom Metadata Type A has a relationship field to Type B, deploy B first or in the same deployment bundle. Out of order deployments often fail with dependency errors.
- Custom settings performance: Because custom settings are cached and can be accessed via
$Setup, they don’t consume SOQL limits but hierarchy resolution still happens per call. Read once into a variable and reuse rather than callinggetInstance()repeatedly in loops. - Permissions & access: Editing custom metadata records requires administrative permissions. If access to the type is restricted, grant the required custom metadata type access through permission sets and verify the behaviour as the intended user.
For callout endpoints, also consider Named Credentials, which carry the URL and the authentication together and avoid hardcoding either.
Troubleshooting
Section titled “Troubleshooting”- “Insufficient access”: The user or integration may not have access to the custom metadata type. Check custom metadata type access in the relevant permission set and confirm whether restricted access is enabled for the type.
- “Record is locked”: The record lives in a managed package or is otherwise read-only. Override by creating your own custom metadata record or custom setting record in your unmanaged namespace.
- “Deployment failed: dependent metadata”: You tried to remove or change a type/field referenced in Flows, Apex, validation rules, or other metadata. Remove or update the references first, then re-deploy.
📋 Governance: Naming, Documentation & Ownership
Section titled “📋 Governance: Naming, Documentation & Ownership”Treat custom metadata and custom settings as shared platform infrastructure, not ad-hoc configuration. A small amount of governance up front prevents “mystery records” and makes it obvious what can be safely changed.
Naming conventions
Section titled “Naming conventions”Use consistent, self explanatory names so admins and developers can recognise intent at a glance.
- Custom metadata types: PascalCase object names; the platform appends the
__mdtsuffix automatically (for example,ApprovalRouting__mdt). - Records (DeveloperName): SCREAMING_SNAKE_CASE keys that read like constants (for example,
FINANCE_ROUTING,ENGINEERING_ROUTING). Treat DeveloperName as a stable API key and choose it carefully; renaming it means coordinating every reference. - Descriptions: Use the Description field on the type and on each record to explain what it controls, where it’s used, and any caveats. Type level descriptions explain the purpose of the configuration; record level descriptions explain how each instance is used.
Example:
| Field | Value |
|---|---|
| Type Name | ApprovalRouting__mdt |
| Record | FINANCE_ROUTING |
| Description | “Finance department approval routing. Controls approver and escalation roles for expense records where Department__c = ‘Finance’. Used by ExpenseApprovalFlow. Created 2026-01-15 by J. Smith.” |
Documentation
Section titled “Documentation”Back your in-org descriptions with a living reference in your documentation tool (Confluence, Notion, internal wiki).
For each custom metadata type or custom setting, capture:
- Purpose – What problem does this configuration solve?
- Records – Which records exist and how each is used (flows, Apex, formulas, validation rules, etc.).
- Owner – Who is accountable for changes (role or named person).
- Change profile – How often it changes (rarely, monthly, per-release) and any related processes.
Keep the in org Description fields aligned with your wiki so someone starting from Setup can quickly find deeper context. Also consider adding a ‘Used in’ section listing Flows, Apex classes, validation rules, or formula fields that reference the type. This becomes invaluable during refactoring.
Ownership & stewardship
Section titled “Ownership & stewardship”Treat each type like a small product with a clear steward.
- Assign every metadata type to an owner (architect, tech lead, admin, or business SME).
- Require at least lightweight review/approval for new records or structural changes.
- Schedule a quarterly review to retire unused records, consolidate duplicates, and confirm that documented usage still matches reality.
Change control
Section titled “Change control”Configuration that drives behaviour should be as traceable as code.
- Track changes in source control wherever possible (Git commits, deployment scripts); for change sets, reference them in your wiki or release notes.
- Capture intent: every change should have a short “why” (linked user story, incident, or design decision).
- Deploy safely: validate changes in a sandbox first, then deploy to production during a planned window if the impact is broad.
- Test paths: for critical config, maintain simple regression checks (Apex tests, Flow tests, or playbook steps) that exercise each key record after deployment.
With clear naming, documentation, ownership, and change control, custom metadata becomes a stable, predictable foundation rather than a source of hidden behaviour.
🧠 Final Thoughts
Section titled “🧠 Final Thoughts”In this part, you learned how Custom Metadata Types and Custom Settings help separate behaviour from hardcoded logic. You compared deployment models, runtime patterns, org-wide settings, user level settings, limits, troubleshooting habits, and the governance needed to keep configuration understandable over time.
Custom configuration should clarify behaviour, not hide it. Used well, metadata becomes a stable control layer: admins can adjust known levers, developers can version important records, and the org can evolve without scattering critical decisions through automation and code.
🚀 Next steps
Section titled “🚀 Next steps”That leads naturally to the final article in the administration track. In Part 7 — Sandbox Strategy & Change Management, you will turn healthy configuration into safe delivery: sandbox strategy, validation, release planning, deployment discipline, and rollback habits that protect production while the org keeps moving.