Mastering Salesforce Administration: Part 6 - Custom Metadata Types & Custom Settings
Updated 20/04/2026
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 optimized 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 behavior | Optimized for read access; changes to records are typically deployment driven | Optimized 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 | Scales well; metadata is immutable | Scales well; query cached |
| Admin Updates | Requires code deploy | Can update via UI setup |
When to use Custom Metadata:
- Feature flags (enable/disable features per org)
- Integration endpoints (URLs, API keys indexed by system)
- 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:
Environment__c(Picklist: Development, UAT, Production) - Field 3:
Description__c(Text, 255 characters) - Field 4:
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
- Record:
New_LWC_Component__mdt- Is_Enabled: ☑ (checked)
- Environment: Production
- Description: “New Lightning Web Component for opportunity dashboard”
- Owner_Email: architect@company.com
- Click New again to create another record
- Record:
Beta_Approval_Flow__mdt- Is_Enabled: ☐ (unchecked)
- Environment: Development
- Description: “New approval process using orchestration (in beta)”
- Owner_Email: architect@company.com
-
Deploy & Version
- Include metadata records in your changeset or package
- Features toggle on/off across environments without code change
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 behavior). 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 (Deprecated): Read-only lookup table (org-wide, one instance). Salesforce disables the creation of new List custom settings 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 organization, 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 behavior 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: noreply@company.com
- Max_Email_Recipients: 100
- Enable_Bounce_Tracking: ☑
- Name:
-
Access in Apex
Email_Configuration__c emailConfig = Email_Configuration__c.getInstance();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)
- Allow users to create personal records that override org defaults
- 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 via DML at runtime in production. Updates must go through metadata changes (change sets, packages, Metadata API) or the Setup UI. Treat the record’s DeveloperName as a stable key, if you rename it, you must also update any Apex, Flow, or configuration that references that record name.
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: Limited by configuration data, not rows. You get roughly 10 million characters of custom metadata across the org, up to 200 custom metadata types (plus more from certified managed packages) and 100 fields per type. (Official limits vary by edition; check System Overview for your org.)
- Custom settings usage: Custom settings count as custom objects and are cached. Cached data is limited to the lesser of 10 MB or 1 MB × number of full featured user licenses, and records count toward your org’s custom object and data storage allocations.
- Query behavior: Standard Apex limits apply. Typical caps are 100 SOQL queries / 50,000 rows per synchronous transaction, 200 SOQL queries / 50,000 rows per asynchronous transaction, and up to 50 million rows via
Database.getQueryLocatorin Batch Apex. - Record size: Custom metadata record “size” is based on the maximum length of its fields. Longer text fields consume your 10M character budget faster.
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 admin level permissions (for example, Customize Application and access to the type). For business users, grant read access via profiles/permission sets and the “Restrict access to custom metadata” schema setting.
Troubleshooting
Section titled “Troubleshooting”- “Insufficient access to field”: The user or integration doesn’t have access to the custom metadata type or its fields. Check the type’s access in the profile/permission set and field level security.
- “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). Remember that DeveloperName becomes the immutable API key, choose it carefully before creating the record. - 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.