Custom Metadata in Salesforce (2025)
Model configuration as metadata you can version, test, and deploy. Learn differences vs Custom Settings, how to create types & records, and how to ship them with the Metadata API and sf CLI.
Deployability
Move config across orgs
Governance
Version control friendly
Performance
Low runtime overhead
Overview: why Custom Metadata
Custom Metadata lets you convert hard-coded logic into deployable configuration. Instead of toggles in code or per-org data, you define a Custom Metadata Type with fields and ship records as metadata. This enables peer reviews, version control, automated tests, and repeatable releases.
Custom Metadata vs Custom Settings
| Aspect | Custom Metadata | Custom Settings |
|---|---|---|
| Deployability | Deployable across orgs (metadata) | Org data (not deployable) |
| Version control | Excellent (source files) | Limited |
| Use cases | Feature flags, routing, limits, mappings | Org/runtime specific settings |
| Security | Avoid secrets/PII | Avoid secrets/PII |
Create Custom Metadata Types & Records
Setup β Custom Metadata Types
Point-and-click creation
- Create a Custom Metadata Type (label, object name, visibility).
- Add custom fields (e.g., Text, Checkbox, Number) for your config.
- Click Manage Records β create records (per environment or global).
- Reference from Apex/Flow using SOQL or metadata relationship fields.
package.xml examples
Include CustomMetadata (records) and CustomObject (the type definition) along with any fields or validation rules your type uses.
<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
<types>
<members>FeatureFlag__mdt.Flag_EnableRouting</members>
<members>FeatureFlag__mdt.Flag_UseNewUI</members>
<name>CustomMetadata</name>
</types>
<types>
<members>FeatureFlag__mdt</members>
<name>CustomObject</name>
</types>
<version>59.0</version>
</Package>Retrieve & deploy with sf CLI
Retrieve (manifest)
MDAPI β convert to source
sf project retrieve start --manifest manifest/package.xml --target-org MySandbox --output-dir mdapi_outsf project convert mdapi --root-dir mdapi_out --output-dir force-appDeploy (validate then resume)
Fast & safe
sf project deploy start --manifest manifest/package.xml --target-org UAT --dry-run --test-level RunLocalTestssf project deploy resume --use-most-recent --target-org UATPre-deploy checklist
- Version bump for your module documented
- Records reviewed for environment-specific values
- Profiles/PermissionSets unaffected or updated
- Validation-only run green (save the deployment ID)
CI/CD workflows
GitHub Actions snippet
JWT auth + validate + deploy
name: deploy-custom-metadata
on:
push:
branches: [ "release/*" ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: salesforcecli/action@v1
- name: Auth JWT
run: |
sf org login jwt --client-id $SF_CONSUMER_KEY \
--jwt-key-file server.key \
--username $SF_USERNAME --alias CI_UAT
- name: Validate
run: |
sf project deploy start --manifest manifest/package.xml \
--target-org CI_UAT --test-level RunLocalTests --dry-run
- name: Resume deploy
if: success()
run: |
sf project deploy resume --use-most-recent --target-org CI_UATCommon pitfalls
Save hours during releases
- Forgetting the
CustomObjectentry for the__mdttype - Environment-specific records accidentally promoted to prod
- Secrets or PII stored in metadata (avoid)
- API version mismatch in
package.xml
Images in org content: quick privacy tip
If your team publishes images (Knowledge, Experience Cloud, Email), scrub hidden EXIF/GPS and authoring traces before upload. Itβs a simple step that prevents accidental location or device leaks in public assets.
FAQ
Ship configuration with confidence
Keep your config as deployable metadata, validate first, and automate. One more thing: keep public images clean of hidden data.