本文へ移動
cccskills
無料GitHub で公開

custom-metadata-types

Use when designing deployable Salesforce configuration with Custom Metadata Types, especially when choosing between CMTs, Custom Settings, and Custom Objects, protecting packaged defaults, or exposing config to Apex, Flow, and formulas. Triggers: 'custom metadata vs custom settings', 'deployable config', 'protected custom metadata', 'feature flags in Salesforce'. NOT for hierarchical Custom Settings resolution, getInstance/getValues, or their SOQL cost — use admin/custom-metadata-types-and-settings. NOT for high-churn transactional or user-managed business records — use admin/object-creation-and-design. NOT for secrets — use integration/named-credentials-setup. More trigger keywords: __mdt, CustomMetadata .md file, customMetadata folder, getInstance, getAll, xsi:type, visibility PackageProtected, MetadataRelationship, EntityDefinition field, $CustomMetadata.

インストール方法を見る

含まれるファイル(8)

  • SKILL.md18.0 KB
  • references/examples.md3.4 KB
  • references/gotchas.md9.2 KB
  • references/llm-anti-patterns.md6.8 KB
  • references/metadata-examples.md13.5 KB
  • references/well-architected.md4.9 KB
  • scripts/check_custom_metadata_types.py12.6 KB
  • templates/custom-metadata-types-template.md1.4 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Use this skill when the org needs configuration that behaves like software, not like business data. Custom Metadata Types are the right answer when values should be versioned, deployed, packaged, and read consistently by Apex, Flow, and formulas without hardcoding environment-specific behavior.


Before Starting

Gather this context before you decide on the storage model:

  • Who changes the values, and how often do they change in production?
  • Do the records need to travel through source control, packaging, or deployment pipelines?
  • Are the values regular configuration, per-user overrides, reportable business data, or secrets such as tokens and passwords?

Questions to Ask Before Configuring

Ask these before creating the type. Each one decides an element you will have to write into the XML, and an LLM that skips them produces a type that deploys and then behaves wrongly in the target org.

AskWhy it mattersWhat a good answer adds
"Will this type ever ship in a managed package?"visibility is Public by default and Protected / PackageProtected only mean anything inside a managed packageThe visibility value, chosen deliberately rather than defaulted
"Which records, if any, must the subscriber be unable to read or change?"Record-level protected is a one-way door: a protected record's developer name cannot change after release and the subscriber cannot create records of a protected typeThe per-record protected flag and a note of what is now frozen
"Which fields will the subscriber be allowed to edit after install?"fieldManageability (Locked / DeveloperControlled / SubscriberControlled) is set per field and is valid only on custom metadata type fieldsA field-by-field manageability decision instead of a silent default
"Can any field value exceed 255 characters?"getAll() and getInstance() truncate every field at 255 characters; only SOQL returns the whole valueThe Apex access pattern, and a decision to move long values elsewhere
"Who reads these records at runtime — Apex, Flow, formulas, or an external system?"A reader on the Enterprise WSDL or SOAP API is cut off by enableAdvancedCMTSecurity, and every non-admin reader needs the type enabled in a permission setThe consumer list and the customMetadataTypeAccesses entries to ship with it
"Does a field need to point at an object or a field on that object?"That is a MetadataRelationship field to EntityDefinition or FieldDefinition, not a Text field holding an API nameThe relationship field definition and its metadataRelationshipControllingField where required
"Who deploys this, and do they hold both permissions?"Creating the type needs "Author Apex"; creating records needs "Customize Application"A deployment identity that can land the whole package, not half of it

What a proper configuration adds over just creating the type in Setup: the records deploy as metadata alongside the code that reads them, the visibility and manageability choices are deliberate rather than defaulted, and every runtime consumer — Apex, Flow, formula, and non-admin user — has been proven to read the values before release.


Core Concepts

Custom Metadata Types are metadata records, not transactional rows. That distinction matters because metadata belongs in source control, deployments, and packaging workflows. If the requirement is "same logic, different environment-safe configuration," CMT is usually the best fit. If the requirement is "users update this every day and report on it," it is usually the wrong fit.

Deployable Configuration, Not User Data

Use CMT when the value should move between sandboxes, scratch orgs, packaging orgs, and production in a controlled way. This is why routing rules, thresholds, feature toggles, and endpoint path fragments fit well. A Custom Object is better when admins or business users need to add and edit records frequently through the UI and treat the records like business data.

CMT, Custom Settings, And Custom Objects Solve Different Problems

Hierarchy Custom Settings still matter when behavior varies by user or profile and the override must be cheap to change in production. Custom Objects fit reportable, user-managed records. CMT fits org-level or package-level configuration that should be promoted like code. The wrong decision usually comes from optimizing for today's convenience instead of the future deployment model.

Protection And Visibility Are Packaging Concerns

Protected custom metadata is useful when a managed package needs internal defaults that subscriber admins should not read or edit. It is not a general-purpose data security boundary for the same org. If the real need is secret management, use Named Credentials or another supported secret store, not public CMT records with masked labels.

The Type Is An Object; The Records Are Separate Components

Three components, three package.xml entries, and one naming asymmetry that causes most first-deploy failures.

Componentpackage.xml <name>Member syntaxFile
The typeCustomObjectRouting_Rule__mdtobjects/Routing_Rule__mdt/Routing_Rule__mdt.object-meta.xml
A fieldCustomFieldRouting_Rule__mdt.Threshold__cobjects/Routing_Rule__mdt/fields/Threshold__c.field-meta.xml
A recordCustomMetadataRouting_Rule.EMEA_HighcustomMetadata/Routing_Rule.EMEA_High.md-meta.xml

The type carries the __mdt suffix; the record name drops it. Type-level settings live on the CustomObject (label, pluralLabel, description, visibility); record-level settings live on the CustomMetadata (label, description, protected, and one <values> block per populated field). Field values are typed with an xsi:type attribute that must match the field definition. Full deployable XML is in references/metadata-examples.md.

Runtime Access Is Easy; Runtime Mutation Is Not

Apex, Flow, and formulas can read CMT records cleanly, but normal business-transaction DML is not the operating model. That is by design. CMT is meant to stabilize configuration, not to become a hidden editable database.


Common Patterns

Metadata-Driven Routing Or Threshold Rules

When to use: A Flow or Apex service needs environment-safe rules such as queue routing, score thresholds, or feature switches.

How it works: Model the rules in a CMT, query them by stable keys such as DeveloperName, and keep the business logic reading configuration instead of embedding IDs and values in code.

Why not the alternative: Hardcoded IDs, labels, or endpoints create deployment drift and sandbox-specific breakage.

Packaged Defaults Plus Subscriber-Safe Extensions

When to use: A managed package needs safe defaults but also wants limited subscriber configuration.

How it works: Keep vendor-owned defaults protected where appropriate, expose only the fields and records that should be subscriber-editable, and separate secrets into Named Credentials.

Why not the alternative: Public metadata for internal defaults leaks implementation details and invites unsupported edits.

Deliberate Migration Off Custom Settings

When to use: Existing org logic reads List or Hierarchy Custom Settings even though the values should really be source-controlled and deployed.

How it works: Inventory the settings, separate true per-user overrides from deployable org config, move the stable org config into CMT, and update Apex/Flow lookups to use metadata keys instead of record IDs.


Decision Guidance

SituationRecommended ApproachReason
Org-wide rules must deploy through Git and CI/CDCustom Metadata TypeConfiguration behaves like metadata and should be promoted with releases
Behavior varies by user or profileHierarchy Custom SettingPer-user and per-profile overrides are the primary requirement
Admins need frequent UI editing and reporting on the recordsCustom ObjectThe records are business data, not release-managed configuration
The value is a password, token, or client secretNamed Credential or supported secret storeCMT is not the right secret boundary
Packaged logic needs internal defaults in a managed packageProtected Custom Metadata where appropriateKeeps package-owned config private while remaining deployable

Recommended Workflow

  1. Confirm CMT is the right store — run the Decision Guidance table above against the answers to ## Questions to Ask Before Configuring. If the answer is a per-user or per-profile override, stop here and use admin/custom-metadata-types-and-settings; if it is a secret in an unpackaged org, use integration/named-credentials-setup.
  2. Fill in the design worksheet — templates/custom-metadata-types-template.md captures the type API name, the key strategy, visibility, per-field fieldManageability, and the runtime access plan for Apex, Flow, and formulas.
  3. Write the type and its fields — copy the shapes from references/metadata-examples.md: the CustomObject with label, pluralLabel, visibility, then one field-meta.xml per field. Choose a MetadataRelationship field over a Text field holding an API name wherever the value points at an object or a field.
  4. Write the records — one .md-meta.xml per record in customMetadata/, each <values> block carrying the correct xsi:type, and <value xsi:nil="true"/> wherever you mean null rather than "leave unchanged".
  5. Run the checker — python3 skills/admin/custom-metadata-types/scripts/check_custom_metadata_types.py --manifest-dir force-app/main/default. It flags records referencing fields that do not exist on the type, empty labels, secret-shaped field names on public types, environment-specific hosts in record values, and DML against __mdt in Apex.
  6. Deploy type, fields, and records in one manifest, then verify — sf project deploy validate first; then confirm with the SOQL and the getInstance assertion at the end of references/metadata-examples.md, and re-run the query as a non-admin user to prove the permission-set custom metadata type access shipped with it.
  7. Read references/gotchas.md before release — the 255-character truncation, the omitted-<values> behaviour, and the three separate protection switches all change what you ship, not just how you test it.

Review Checklist

Run through these before marking work in this area complete:

  • The requirement is truly configuration, not business data with reporting and CRUD needs.
  • The chosen storage model matches the deployment and ownership model, not just developer convenience.
  • Stable keys such as DeveloperName are part of the lookup contract.
  • No secrets, passwords, or tokens are being stored in public CMT records.
  • Apex, Flow, and formulas read metadata intentionally and do not depend on environment-specific IDs.
  • Any packaging visibility choice is documented, especially for protected defaults.
  • visibility on the type and protected on each record were chosen deliberately, not left at the default.
  • Every <values> block has an xsi:type matching its field, and every field meant to be null uses xsi:nil.
  • Any field that can exceed 255 characters is read with SOQL, not getAll() / getInstance().
  • The permission set or profile that non-admin readers hold enables this custom metadata type.
  • The type, its fields, and its records deploy from one manifest, and the deploy was validated before the real run.

Salesforce-Specific Gotchas

Non-obvious platform behaviors that cause real production problems:

  1. CMT records are metadata, not runtime DML targets - teams design them like editable rows and then discover the write path does not fit normal transaction logic.
  2. Protected metadata is a package boundary, not an org security model - it helps managed-package encapsulation but does not replace proper secret handling or field security strategy.
  3. DeveloperName becomes part of the contract - once code, Flow, or formulas key off metadata names, renaming records casually creates breakage.
  4. A deployable model is slower to change by design - if operations needs hourly production edits by non-release users, the wrong storage type may have been chosen.
  5. The cached accessors truncate at 255 characters - getAll() and getInstance() cut every field; only SOQL returns the full value, and SOQL against __mdt is unlimited per transaction.
  6. Leaving a <values> block out does not clear the field - it stays at its previous value on an update and lands as null on a first deploy; xsi:nil is the only explicit clear.
  7. visibility and protected are two switches, not one - plus PackageProtected, which the Metadata API guide names as the value for securing API keys and tokens inside a managed package.
  8. A __mdt object can be unreadable without any sharing rule - PermissionSetCustomMetadataTypeAccess gates record readability per type from API 47.0, and enableAdvancedCMTSecurity hides values from the SOAP API org-wide.

Deeper treatment, with the source for each, in references/gotchas.md.


Output Artifacts

ArtifactDescription
Configuration storage decisionRecommendation for CMT vs Custom Setting vs Custom Object vs Named Credential
Metadata modelSuggested type, fields, keys, and visibility model for the configuration
Refactor findingsConcrete issues such as hardcoded IDs, public secrets, or wrong storage fit
Deployable metadataobjects/<Type>__mdt/ with its fields/, customMetadata/<Type>.<Record>.md-meta.xml, and the package.xml carrying all three

Reference Files

FileRead it when
references/metadata-examples.mdWriting or reviewing the deployable XML for the type, its fields, its records, and the package.xml
references/gotchas.mdTen platform behaviours that change what you ship — truncation, xsi:nil, the protection switches, permission-set access
references/examples.mdWorking through a routing-rules or packaged-defaults scenario end to end
references/well-architected.mdJustifying the storage choice against Operational Excellence, Reliability, and Security, or citing the official sources
references/llm-anti-patterns.mdSelf-checking generated output for DML on __mdt, wrong storage choice, or missing no-code access paths

Related Skills

  • admin/custom-metadata-types-and-settings - the Custom Settings side of the comparison: hierarchical resolution, getValues/getInstance, and their governor-limit cost.
  • apex/custom-metadata-in-apex - use when the storage decision is made and the main question is Apex access and caching patterns.
  • apex/apex-dml-patterns - why standard DML never applies to __mdt and what the Metadata.DeployContainer path costs instead.
  • admin/change-management-and-deployment - use when the release process and environment promotion model are the harder problem.
  • devops/unlocked-package-development - packaging the type and its records, where visibility and record protected start to matter.
  • admin/assignment-rules - a common consumer: routing configuration modelled as CMT records instead of hardcoded queue Ids.
  • admin/object-creation-and-design - when the records turn out to be business data that users edit and report on.
  • integration/named-credentials-setup - where endpoint hosts and credentials belong instead of CMT fields.
  • admin/process-automation-selection - use when Flow or Apex design is the main decision and CMT is only one part of the solution.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Use this skill when writing test-first, behavior-driven acceptance criteria in Given/When/Then format for a Salesforce user story. Covers happy path, edge cases, negative paths, permission boundaries, and data-state preconditions so the AC block can drive UAT scripts and Apex test design downstream. Trigger keywords: given when then, gherkin, behavior driven AC, test first acceptance criteria, scenario outline, BDD acceptance criteria. NOT for the user-story format itself (use admin/user-story-writing-for-salesforce). NOT for UAT script writing (use admin/uat-test-case-design). NOT for Apex test method generation (use agents/test-class-generator). NOT for high-level UAT planning (use admin/uat-and-acceptance-criteria). More triggers: acceptance criteria record, ac_id, req_id on a criterion, artefact under test, negative case for a rule-type requirement, no-match fall-through criterion, oracle for a Then clause, test type apex flow manual, criteria linter, check_ac_format.py, --manifest-dir.

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

Task and Event objects: polymorphic WhatId/WhoId, Activity object model, ActivityHistory vs OpenActivity, activity timeline customization, bulk task creation, Einstein Activity Capture boundaries. NOT for turning on EAC or calendar sync — use admin/einstein-activity-capture-setup. NOT for Email-to-Case — use admin/case-management-setup. Covers ActivitiesSettings metadata, enableActivities, shared Task/Event custom fields and FLS, TaskStatus value sets, Shared Activities and TaskRelation/EventRelation, recurring and child activities, and partial-success bulk DML on Task.

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

Design Invocable Apex actions that return deterministic, agent-friendly errors instead of surfacing raw exceptions to the LLM. NOT for authoring the action itself — @InvocableMethod schema, labels, security context — use agentforce/custom-agent-actions-apex. NOT for the Apex tests that force each error branch — use agentforce/agent-action-unit-tests.

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

Use when designing how an Agentforce agent extracts structured input parameters (slots) from a user's natural-language utterance to invoke an action. Triggers: 'agent extract date from user', 'agent action argument extraction', 'agentforce slot filling', 'agent invocable input mapping', 'agent fails to fill required parameter'. NOT for action authoring (use agentforce/agent-actions) or for prompt-template variable binding (use agentforce/prompt-builder-templates).

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

Apex test patterns for @InvocableMethod agent actions: per-reason-code branch coverage, bulk safety, callout mocking, deterministic assertions. NOT for testing whether the agent routes to the right topic or answers well — use agentforce/agent-testing-and-evaluation. NOT for designing the error envelope the tests assert on — use agentforce/agent-action-error-handling.

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

Designing or reviewing Agentforce actions: Flow actions, Apex invocable actions, prompt-template actions, action naming, input and output contracts, confirmation requirements, and safe error behavior. Triggers: 'agent actions', 'build an agent that can look up an order', 'make the agent able to check order status', 'give the agent a capability', 'agent that can retrieve a record', 'flow action for agent', 'agent invocable action', 'action schema design'. NOT for writing the Apex class itself — use agentforce/custom-agent-actions-apex. NOT for the reason_code error envelope that stops an agent retry loop — use agentforce/agent-action-error-handling.

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

PranavNagrecha のスキルをすべて見る

このスキルの問題を報告する