platform-flexipage-generate
forcedotcom/sf-skills
Create, generate, and customize Salesforce Lightning FlexiPages with CLI-driven metadata generation.
What is platform-flexipage-generate?
This skill generates and modifies Salesforce Lightning pages (RecordPage, AppPage, HomePage) by bootstrapping valid FlexiPage XML structure via CLI templates, then adding or customizing components. Use it when users need to create or edit Lightning pages, add components, troubleshoot deployment errors, or work with .flexipage-meta.xml files.
- Bootstrap new FlexiPages using CLI templates to ensure valid XML structure and proper regions
- Generate RecordPage, AppPage, and HomePage metadata with correct component configuration
- Add and configure components dynamically to existing FlexiPages
- Deploy and validate FlexiPage changes with dry-run testing
- Troubleshoot FlexiPage deployment errors and XML structure issues
- Edit and update existing .flexipage-meta.xml files with proper field references and identifiers
How to install platform-flexipage-generate
npx skills add https://github.com/forcedotcom/sf-skills --skill platform-flexipage-generate- Salesforce CLI (sf) version 2.126.4 or higher
- Python 3.10.0 or higher
- Templates plugin for sf CLI (installed via `sf plugins install templates`)
- Valid sfdx-project.json with packageDirectories configured
- Access to a Salesforce org for deployment and validation
How to use platform-flexipage-generate
- 1.Read sfdx-project.json to identify the package directory path (e.g., force-app)
- 2.Run `sf template generate flexipage` with appropriate template type (RecordPage, AppPage, or HomePage) and field parameters
- 3.Validate field names exist on the target SObject using MCP tools or describe commands before running the template command
- 4.Execute a dry-run deployment with `sf project deploy start --dry-run` to validate the generated FlexiPage XML
- 5.Fix any deployment errors by reviewing the XML structure, identifiers, and field references against the validation checklist
- 6.Add additional components dynamically if requested, using the component discovery and inference pipeline
- 7.Deploy the final FlexiPage to the org once validation passes
Use cases
- Create a new RecordPage for a custom Salesforce object with primary, secondary, and detail fields
- Add a richText component or dynamicHighlights section to an existing Lightning page
- Customize a HomePage or AppPage with additional components and field sections
- Validate and fix FlexiPage XML deployment errors before pushing to production
- Generate a multi-column fieldSection layout for displaying related record data
- Salesforce developers building Lightning pages
- Admins customizing record pages and app pages
- Teams deploying FlexiPage metadata via CI/CD pipelines
- Developers troubleshooting page layout and component configuration issues
platform-flexipage-generate FAQ
Always use the CLI template command (`sf template generate flexipage`) when creating NEW FlexiPages. The CLI generates valid XML structure, proper regions, and correct metadata that prevents deployment errors. Only edit XML directly when modifying existing .flexipage-meta.xml files.
Specify `--primary-field` (most important identifying field like Name), `--secondary-fields` (4-6 fields for record summary, max 12), and `--detail-fields` (full record details including all required fields). Always validate that fields exist on the SObject before running the command.
A dry-run deployment validates the FlexiPage XML and all dependencies without actually deploying to the org. It catches structural errors, missing field references, and identifier conflicts before you push to production.
Review the deployment error message, check the XML structure against the validation checklist (unique identifiers, correct field references using Record.{Field} format, proper region/facet nesting), and consult references/xml_rules.md for encoding and structure rules.
Yes. After the base page deploys successfully, you can add additional components dynamically using the component discovery and inference pipeline. Never write component XML from memory alone.
Full instructions (SKILL.md)
Source of truth, from forcedotcom/sf-skills.
name: platform-flexipage-generate description: "Use when users create, generate, modify, or validate Salesforce Lightning pages (FlexiPages). Trigger on RecordPage, AppPage, HomePage, Lightning pages, adding components to a page, page customization (e.g. 'customize the record page'), or .flexipage-meta.xml files (regions, components, deployment errors). DO NOT TRIGGER for Visualforce pages, page layout assignments in the UI, UI Bundle/Experience Cloud site pages, or Aura/Lightning Web Component development without FlexiPage context." allowed-tools: Bash Read Write metadata: version: "1.1" domains: ["Platform"] minApiVersion: "60.0" cliTools: - tool: ["python3"] semver: ">=3.10.0" - tool: ["sf"] semver: ">=2.126.4" mcpTools: metadata-experts: tools: ["execute_metadata_action"] semver: ">=1.0.0"
When to Use This Skill
Use this skill when you need to:
- Create Lightning pages (RecordPage, AppPage, HomePage)
- Generate FlexiPage metadata XML
- Add components to existing FlexiPages
- Troubleshoot FlexiPage deployment errors
- Understand FlexiPage structure and component configuration
- Work with page layouts or Lightning page customization
- Edit or update ANY *.flexipage-meta.xml file
Specification
Overview
CRITICAL: When creating NEW FlexiPages, you MUST ALWAYS start with the CLI template command. Never create FlexiPage XML from scratch - the CLI provides valid structure, proper regions, and correct component configuration that prevents deployment errors.
Generate Lightning pages (RecordPage, AppPage, HomePage) using CLI bootstrapping for component discovery and configuration.
Quick Start Workflow
Step 1: Bootstrap with CLI
MANDATORY FOR NEW PAGES: This step is NOT optional. Always use the CLI template command when creating a new FlexiPage. The CLI generates valid XML structure, proper regions, and correct metadata that prevents common deployment errors. Only skip this step if you're editing an existing FlexiPage file.
<packageDirectory> = the path value from sfdx-project.json → packageDirectories[0] (e.g., force-app). Read it from the project file before running commands.
sf template generate flexipage \
--name <PageName> \
--template <RecordPage|AppPage|HomePage> \
--sobject <SObject> \
--primary-field <Field1> \
--secondary-fields <Field2,Field3> \
--detail-fields <Field4,Field5,Field6,Field7> \
--output-dir <packageDirectory>/main/default/flexipages
CRITICAL: If the sf template generate flexipage command fails, STOP.
- Install the templates plugin:
sf plugins install templates - Retry the
sf template generate flexipagecommand - Verify the FlexiPage XML file was created
Do NOT continue to Step 2 until the template command succeeds. The generated XML is required for the entire workflow.
Template-specific requirements
RecordPage:
- Requires
--sobject(e.g., Account, Custom_Object__c) - Requires field parameters:
--primary-field: Most important identifying field (e.g., Name)--secondary-fields: Record summary (recommended 4-6, max 12)--detail-fields: Full record details, including required fields (e.g., Name)
AppPage:
- No additional requirements
HomePage:
- No additional requirements
Field Selection Rules
- Validate fields exist: Use MCP tools or describe commands to discover available fields for the object before specifying them in the command
- Prefer compound fields: Use
Name(notFirstName/LastName),BillingAddress(notBillingStreet/BillingCity/BillingState),MailingAddress, etc. when available - Include required fields in detail-fields: Always include object required fields (like
Name) in the--detail-fieldsparameter, even if they're also used in--primary-fieldor--secondary-fields
What you get
- Valid FlexiPage XML with correct structure
- Pre-configured regions and basic components
- Proper field references and facet structure
- Ready to deploy as-is or enhance further
Step 2: Deploy Base Page
Run a dry-run deployment to validate the page and dependencies (use the default package directory from sfdx-project.json):
sf project deploy start --dry-run -d "<packageDirectory>/main/default" --test-level NoTestRun --wait 10 --json
Critical: Fix any deployment errors before proceeding. The page must validate successfully.
Step 3: Add Components Dynamically (if requested)
After the base page deploys successfully, if the user wants additional components, follow the Adding Components Dynamically workflow below. All component additions MUST go through the discovery and inference pipeline — never write component XML from memory alone.
Critical XML Rules
Read references/xml_rules.md for all XML encoding rules, field reference format, region/facet types, fieldInstance structure, unique identifier requirements, and common deployment error resolutions.
Key rules (quick reminder):
- Encode HTML in
<value>tags:&first, then<,>,",' - Field references:
Record.{FieldApiName}(neverObject.Field) - Every
<identifier>and region<name>must be unique across the file - Multiple components in same facet → combine in ONE region with multiple
<itemInstances>
Identifiers, Regions, and Containers
Read references/identifiers_and_regions.md for the identifier generation algorithm, facet naming patterns (named vs UUID), region selection rules, and container component facet structure.
Component-Specific Tips
dynamicHighlights (RecordPage Header)
Location: header region only. See references/record_flexipage_dynamicHighlights.md for full structure.
CLI generates Facets automatically from --primary-field and --secondary-fields.
fieldSection
Use for: Displaying fields in columns. Three-level nesting: Region → Column Facets → Field Facets.
See references/flexipage_fieldSection.md for full structure and XML example.
Critical: The columns property value is a Facet name, not a number.
richText
See references/flexipage_richText.md for encoding rules and XML structure.
Identifier: flexipage_richText or flexipage_richText_{N}
Required Metadata Structure
<FlexiPage xmlns="http://soap.sforce.com/2006/04/metadata">
<flexiPageRegions>
<!-- Regions and components here -->
</flexiPageRegions>
<masterLabel>Page Label</masterLabel>
<template>
<name>flexipage:recordHomeTemplateDesktop</name>
</template>
<type>RecordPage</type>
<sobjectType>Object__c</sobjectType> <!-- RecordPage only -->
</FlexiPage>
Page Types:
RecordPage- requires<sobjectType>AppPage- no sobjectTypeHomePage- no sobjectType
Validation Checklist
Structure (new pages)
- Used CLI to bootstrap — never create FlexiPage XML from scratch
Identifiers & Regions
- All
<identifier>values unique across entire file - All region/facet
<name>values unique across entire file - Multiple components in same facet combined in ONE region with multiple
<itemInstances>
Field Instances
- All field references use
Record.{Field}format - Each fieldInstance has
fieldInstancePropertieswithuiBehavior - Each fieldInstance in its own
<itemInstances>wrapper
Types & Encoding
- Template regions use
<type>Region</type>; component facets use<type>Facet</type> - Property values with HTML/XML are entity-encoded
- No unnecessary
<mode>tags (only where component patterns require them) - No
__csuffix in page names - Each Facet referenced by exactly one component property
Quick Reference: CLI Command
Read references/cli_commands.md for full CLI examples (RecordPage, AppPage, HomePage) and available options.
Adding Components Dynamically
MANDATORY WORKFLOW: ALL component additions to a FlexiPage MUST follow this workflow. Do not write component XML from memory or skip discovery. This applies to standard OOTB components, custom LWC components, and any other component type.
Overview
When the user requests components (e.g., "add a related list of contacts and a report"), follow this pipeline:
1. Parse Intent → identify ALL requested components
2. Discover ALL → batch components through 3-tier discovery
3. Infer Properties → run 3-step inference for EACH discovered component
4. Generate XML → produce valid XML for all components together
5. Validate → check identifiers, regions, property completeness
Key rule: Discover ALL components as a batch first (one scan, one MCP call), THEN infer properties for each. Do not invoke discovery steps per-component or interleave discovery and inference.
Step 1: Parse User Intent
Extract every component request from the user's utterance. Examples:
- "Create Account page with a report and related contacts" → 2 components: report, related list
- "Add activities, chatter, and a DRL of Cases" → 3 components: activities, chatter, dynamic related list
Step 2: 3-Tier Component Discovery
Complete each tier for ALL components before moving to the next tier — do NOT run Tier 1→2→3 per component:
| Tier | Source | When | Calls |
|---|---|---|---|
| 1 | Local workspace scan | Always first — run for ALL components | 0 (local only) |
| 2 | discoverUiComponents MCP action | Single call for all components unresolved after Tier 1 | 1 |
| 3 | Generate new LWC bundle | Only for components still unresolved after Tier 2 + user confirms | 0 |
After Tier 1 completes for all components, collect only the unresolved ones and pass them to Tier 2 in a single MCP call. Only components still unresolved after Tier 2 proceed to Tier 3.
See Local Workspace Scanner and MCP Action Integration sections below for details.
Step 3: Property Inference (per component)
For EACH discovered component, infer properties using the 3-step strategy:
- Fetch schema or read source — For Tier 2 (org) components, call
getUiComponentSchemas; for Tier 1 (local), extract@apiprops from source - Apply component instructions — If
references/<name>.mdexists, read and follow its inference rules - Resolve remaining — Smart defaults → LLM inference → user prompts (last resort)
See Hybrid Property Inference Strategy below for full details.
Step 4: Generate XML
What you CANNOT do:
- Modify top level structure in the XML file
- Add any components from memory which is not resolved from 3-Tier Component Discovery
- Make any enhancements
Read references/xml_rules.md before writing any XML. Follow all element naming and structure rules defined there.
Produce <itemInstances> XML for all resolved components:
- Use
<componentInstanceProperties>for every property (NOT<properties>) - Assign unique identifiers across the full set (see references/identifiers_and_regions.md)
- Insert into appropriate regions (header, main, sidebar, or facets)
- Follow each component's XML structure from its instructions file or schema
Step 5: Validate
Check the complete FlexiPage for:
- Identifier uniqueness (no duplicates across entire file)
- Region validity (components in correct regions)
- Property completeness (all required properties populated)
- XML encoding (HTML values entity-encoded)
- Element name correctness (see references/xml_rules.md §6)
Deploy with dry-run (use default package directory from sfdx-project.json):
sf project deploy start --dry-run -d "<packageDirectory>/main/default" --test-level NoTestRun --wait 10 --json
MCP Action Integration
Read references/mcp_action_examples.md for full input/output examples and parameter tables.
Two MCP actions via execute_metadata_action:
| Action | Purpose | When |
|---|---|---|
DISCOVER_UI_COMPONENTS | Find components for a page type | Tier 2 discovery — single call for all unresolved components |
GET_UI_COMPONENT_SCHEMAS | Get property schemas | Property inference Step 1 (Tier 2 org components only) |
Key conventions:
- Component definition format:
namespace/blockName(forward-slash) in MCP calls,namespace:blockName(colon) in XML pageContextwithentityNameis required for RECORD_PAGEgetUiComponentSchemassupports partial failures — check each component'ssuccessboolean
Local Workspace Scanner
Scans the local SFDX project for custom LWC components before making any MCP calls (Tier 1 discovery).
Algorithm
Run the scanner for each component query (local scan — no network calls):
scripts/scan-lwc-components.sh "<query>" [packageDirectory]
The script scans <packageDirectory>/**/lwc/*/, tokenizes camelCase component names, scores them against user intent keywords, and returns a JSON array of matches with confidence tiers:
- High confidence (≥70%): auto-select, confirm with user
- Medium confidence (40-69%): present ranked list for user selection
- Low confidence (<40%): skip, proceed to Tier 2
Run Tier 1 for ALL components before moving any to Tier 2. Collect all unresolved components from Tier 1, then pass them to Tier 2 in a single MCP call.
Disambiguation
For medium-confidence matches (40-69%) or multiple high-confidence matches:
- Read each candidate's
.js-meta.xmlfor<description>and<targetConfigs> - Present ranked list to user with component name + description
- User selects or says "none of these" (→ proceed to Tier 2)
When to Skip
Skip local scan when:
- User explicitly mentions an org-level component ("use the standard report component")
- User intent clearly maps to a known standard component (DRL, richText, etc.)
- No
<packageDirectory>directory exists in the workspace
Hybrid Property Inference Strategy
For EACH discovered component, populate its properties using this 3-step strategy in order:
Step 1: Fetch Latest Schema (conditional)
Call getUiComponentSchemas only when the component does not exist on the local machine (i.e., Tier 2 org-discovered components). For local components (Tier 1), extract @api properties directly from the source code instead.
When to call:
- Tier 2 (org discovery): Always — the schema is the only source of property info
- Tier 1 (local): Skip — read
@apiproperties from the component's.jssource file - Tier 3 (generated): Skip — you just created the source, so properties are already known
Step 2: Apply Component Instructions (if present)
Run scripts/resolve-component-instructions.sh <namespace:component> — it returns the instructions file path if it exists, or empty string.
Examples:
record_flexipage:dynamicHighlights→references/record_flexipage_dynamicHighlights.mdflexipage:fieldSection→references/flexipage_fieldSection.mdc:expenseTracker→ (empty — no file)
If a file is returned: read and follow its inference rules, XML patterns, and defaults. If empty: skip directly to Step 3.
Instructions files augment the schema — they provide how to derive values from user intent. Any properties in the schema not covered by the instructions file are resolved in Step 3.
Step 3: Resolve Remaining Properties
For any properties not yet resolved, apply in this priority order:
3a. Smart Default Heuristics:
| Property Pattern | Default Value |
|---|---|
recordId | {!recordId} |
objectApiName / sObjectName | Page's <sobjectType> value |
show* / visible* / display* | true |
hide* / hidden* / disabled* | false |
| Boolean without prefix | false |
Schema specifies "default" | Use schema default |
3b. LLM Inference:
Use the component schema + user intent + page context to infer reasonable values. Example: user says "report showing top opportunities" → infer reportName should reference an opportunities report.
3c. User Prompts (last resort): Only prompt the user for critical required properties that cannot be inferred. If user says "skip", omit the component entirely.
Tier-Specific Behavior
| Tier | Extra Step | Schema Call | Instructions |
|---|---|---|---|
| Tier 1 (local) | Extract @api props from source | No (use source) | If exists |
| Tier 2 (org) | — | Yes | If exists |
| Tier 3 (generated) | Extract @api from just-generated source | No (just created) | No |
New LWC Generation (Tier 3)
When no component is found locally (Tier 1) or in the org (Tier 2), offer to generate a new LWC.
Trigger Conditions
- Tier 1 and Tier 2 both miss or user rejected all candidates
- User has not explicitly said "skip" or "don't create"
Confirmation
Always confirm before creating. Explain: component name. If user declines: skip, continue with other components.
Post-Generation
After creating the LWC bundle:
- Treat as a Tier 1 local component immediately
- Extract
@apiproperties from the generated source - Apply smart defaults for
recordIdandobjectApiName - Generate FlexiPage XML with
c:{componentName}as the componentName
Naming Convention
- Derive from user intent: "customer health score" →
customerHealthScore - camelCase, no hyphens, no underscores in the JS class name
- Folder name matches class name (lowercase first letter):
customerHealthScore/
Reference File Index
| File | When to read |
|---|---|
references/xml_rules.md | Before writing or editing any FlexiPage XML — encoding, field refs, identifiers, deployment errors |
references/identifiers_and_regions.md | When adding components — identifier algorithm, facet naming, region selection, container pattern |
references/cli_commands.md | When bootstrapping new pages — full CLI examples for RecordPage, AppPage, HomePage |
references/mcp_action_examples.md | When calling MCP actions — full input/output JSON for discoverUiComponents and getUiComponentSchemas |
references/flexipage_fieldSection.md | When adding a Field Section with columns |
references/record_flexipage_dynamicHighlights.md | When adding a Dynamic Highlights panel |
references/flexipage_richText.md | When adding a Rich Text component |
scripts/scan-lwc-components.sh | Tier 1 local workspace scan — tokenizes and scores LWC component names against user query |
scripts/resolve-component-instructions.sh | Property inference Step 2 — resolves component definition to instructions file path |
To add a new component pattern: Create references/<namespace>_<componentName>.md following the structure in existing files. The skill automatically checks for the file during Step 2 of property inference.
Validation Rules for Dynamic Components
After generating XML for dynamically added components, verify ALL of the following before deployment:
Identifier Uniqueness
- Extract ALL
<identifier>values from the entire FlexiPage file - Confirm zero duplicates
- If conflict: auto-increment suffix (
_2,_3, etc.)
Region Validity
- Components placed in correct regions for their type:
record_flexipage:dynamicHighlights→headeronlyflexipage:fieldSection→mainor tab facetsflexipage:richText→ any region
Property Completeness
- All properties marked required in schema have values
- All values match expected types (String, Boolean, valueList, Integer)
- No raw HTML in
<value>tags (must be entity-encoded)
Structural Integrity
- Every Facet referenced by a component property exists as a
<flexiPageRegions>block - No orphan Facets (every Facet is referenced by exactly one component)
- Multiple components in same region use ONE
<flexiPageRegions>block with multiple<itemInstances>
Cross-Component Consistency
- For multi-component additions: identifiers are unique across ALL new components
- Facet UUIDs don't collide between components
- Components that require singleton placement (dynamicHighlights, recordDetailPanelMobile) are not duplicated
Related skills
More from forcedotcom/sf-skills and the wider catalog.

platform-lightning-app-coordinate
Build complete Salesforce Lightning Experience applications from natural language descriptions.

platform-lightning-type-widget-coordinate
Coordinate Apex-backed Lightning Type and HXL widget generation for Salesforce.

platform-list-view-generate
Create and validate Salesforce List View metadata for filtered record listings.

platform-lsp-integrate
Reference for Salesforce LSP MCP tools, error codes, and fallback patterns.

platform-manifest-generate
Generate Salesforce package.xml and destructive manifests from source, component lists, or org introspection.

platform-mcp-tool-widget-coordinate
Orchestrate Lightning Type + HXL widget generation for custom MCP server tool output backed by Apex Invocable Actions.