lightning-flow-scanner
v6.11.4
Published
A Salesforce CLI plugin for analysis and optimization of Salesforce Flow. Scans metadata for 20+ issues such as hardcoded IDs, unsafe contexts, inefficient SOQL/DML operations, recursion risks, and missing fault handling. Supports auto-fixes, rule configu
Readme
Table of contents
Usage
Lightning Flow Scanner CLI is plug-and-play. Just open any Salesforce project and run:
sf flow:scanAll default rules are applied automatically.
sf flow:scan # Scan flows in the current directory
sf flow:scan --sarif > report.sarif # Export scan results as SARIF
sf flow scan --csv > results.csv # Export scan results as CSV
sf flow doc > flow-docs.md # Generate flow documentation (Single markdown file)
sf flow doc --output flow-docs --separate # Generate one Markdown file per flow
sf flow:fix -d src/force-app # Fix flows in a specific directory| Flag | Alias | Description | Example |
|-----------------|-------|-----------------------------------------------|-------------------------------------|
| --config | -c | Path to config file | -c .flow-scanner.yml |
| --directory | -d | Directory to scan | -d force-app |
| --files | -p | Specific flow files | -p "flows/MyFlow.flow-meta.xml" |
| --csv | -v | CSV output | --csv > violations.csv |
| --sarif | -s | SARIF output (GitHub, etc.) | --sarif > report.sarif |
| --json | | Pretty JSON output | --json |
| --threshold | -t | Fail on error/warn | --threshold error |
| --betaMode | -z | Enable beta rules | --betaMode |
| --loglevel | | Logging level | --loglevel debug |
Privacy: Zero user data collected. All processing is client-side. → See our Security Policy.
Default Rules
Want to code a new rule? → See How to Write a Rule
Action Calls In Loop
ActionCallsInLoop – To prevent exceeding Apex governor limits, it is advisable to consolidate and bulkify your apex calls, utilizing a single action call containing a collection variable at the end of the loop.
Severity: 🔴 Error
Outdated API Version
APIVersion – Introducing newer API components may lead to unexpected issues with older versions of Flows, as they might not align with the underlying mechanics. Starting from API version 50.0, the Api Version attribute has been readily available on the Flow Object. To ensure smooth operation and reduce discrepancies between API versions, it is strongly advised to regularly update and maintain them.
Severity: 🟡 Warning
Auto Layout
AutoLayout – With Canvas Mode set to Auto-Layout, elements are spaced, connected, and aligned automatically, keeping your Flow neatly organized—saving you time.
Severity: 🔵 Note
Copy API Name
CopyAPIName – Maintaining multiple elements with a similar name, like Copy_X_Of_Element, can diminish the overall readability of your Flow. When copying and pasting these elements, remember to update the API name of the newly created copy.
Severity: 🟡 Warning
Cyclomatic Complexity
CyclomaticComplexity – The number of loops and decision rules, plus the number of decisions. Use a combination of 1) subflows and 2) breaking flows into multiple concise trigger-ordered flows to reduce cyclomatic complexity within a single flow, ensuring maintainability and simplicity.
Severity: 🔵 Note
DML Statement In A Loop
DMLStatementInLoop – To prevent exceeding Apex governor limits, consolidate all your database operations—record creation, updates, or deletions—at the conclusion of the flow.
Severity: 🔴 Error
Duplicate DML Operation
DuplicateDMLOperation – When a flow executes database changes or actions between two screens, prevent users from navigating backward between screens; otherwise, duplicate database operations may be performed.
Severity: 🟡 Warning
Flow Naming Convention
FlowName – The readability of a flow is paramount. Establishing a naming convention significantly enhances findability, searchability, and overall consistency. Include at least a domain and a brief description of the flow’s actions, for example Service_OrderFulfillment.
Severity: 🔴 Error
Get Record All Fields
GetRecordAllFields – Following the principle of least privilege (PoLP), avoid using Get Records with “Automatically store all fields” unless necessary.
Severity: 🟡 Warning
Hardcoded Id
HardcodedId – Avoid hard-coding IDs because they are org specific. Instead, pass them into variables at the start of the flow—via merge-field URL parameters or a Get Records element.
Severity: 🔴 Error
Hardcoded Url
HardcodedUrl – Avoid hard-coding URLs because they are environment specific. Use an $API formula (preferred) or environment-specific sources like custom labels, metadata, or settings.
Severity: 🔴 Error
Inactive Flow
InactiveFlow – Like cleaning out your closet: deleting unused flows is essential. Inactive flows can still cause trouble—such as accidentally deleting records during testing, or being activated as subflows.
Severity: 🟡 Warning
Missing Fault Path
MissingFaultPath – A flow may fail to execute an operation as intended. By default, the flow displays an error to the user and emails the creator. Customize this behavior by incorporating a Fault Path.
Severity: 🟡 Warning
Missing Filter Record Trigger 
MissingFilterRecordTrigger – Record-triggered flows that lack filters on changed fields or entry conditions can lead to unnecessary executions on every record change. This may degrade system performance, hit governor limits faster, and increase resource consumption in high-volume orgs. Severity: 🟡 Warning
Missing Flow Description
FlowDescription – Descriptions play a vital role in documentation. It is highly recommended to include details about where a flow is used and its intended purpose.
Severity: 🔴 Error
Missing Metadata Description 
MissingMetadataDescription – Flags Flow elements (Get Records, Assignments, Decisions, Actions, etc.) and metadata components (Variables, Formulas, Constants, Text Templates) that lack a description. Adding concise descriptions greatly improves readability, maintainability, and helps AI tools understand your automation intent.
Severity: 🔴 Error
Missing Null Handler
MissingNullHandler – When a Get Records operation finds no data, it returns null. Validate data by using a Decision element to check for a non-null result.
Severity: 🟡 Warning
Process Builder
ProcessBuilder – Salesforce is transitioning away from Workflow Rules and Process Builder in favor of Flow. Begin migrating your organization’s automation to Flow.
Severity: 🟡 Warning
Record ID as String 
RecordIdAsString – Detects flows using a String variable named recordId as input when they could receive the entire record object instead. Since recent Salesforce releases, record pages and quick actions can pass the complete record, eliminating the need for an additional Get Records query and improving performance.
Severity: 🔵 Note
Recursive After Update
RecursiveAfterUpdate – After-update flows are meant for modifying other records. Using them on the same record can cause recursion. Consider before-save flows for same-record updates.
Severity: 🟡 Warning
Same Record Field Updates
SameRecordFieldUpdates – Similar to triggers, before-save contexts can update the same record via $Record without invoking DML.
Severity: 🟡 Warning
SOQL Query In A Loop
SOQLQueryInLoop – To prevent exceeding Apex governor limits, consolidate all SOQL queries at the end of the flow.
Severity: 🔴 Error
Transform Instead of Loop 
TransformInsteadOfLoop – Detects Loop elements that directly connect to Assignment elements. Transform elements handle collection manipulation in bulk operations, providing significant performance improvements over iterative loop-assignment patterns.
Severity: 🔵 Note
Trigger Order
TriggerOrder – Guarantee your flow execution order with the Trigger Order property introduced in Spring ’22.
Severity: 🔵 Note
Unconnected Element
UnconnectedElement – Avoid unconnected elements that are not used by the flow to keep flows efficient and maintainable.
Severity: 🟡 Warning
Unsafe Running Context
UnsafeRunningContext – This flow is configured to run in System Mode without Sharing, granting all users permission to view and edit all data. This can lead to unsafe data access.
Severity: 🔴 Error
Unused Variable
UnusedVariable – To maintain efficiency and manageability, avoid including variables that are never referenced.
Severity: 🟡 Warning
Configuration
It is recommend to configure and define:
- The rules to be executed.
- The severity of violating any specific rule.
- Rule properties such as REGEX expressions.
- Any known exceptions that should be ignored during scanning.
{
"rules": {
// Your rules here
},
"exceptions": {
// Your exceptions here
}
}Most Lightning Flow Scanner distributions automatically resolve configurations from .flow-scanner.yml, .flow-scanner.json, or package.json → flowScanner.
By default, all default rules are executed. You can customize individual rules and override the rules to be executed without having to specify every rule. Below is a breakdown of the available attributes of rule configuration:
{
"rules": {
"<RuleName>": {
"severity": "<Severity>", // Override severity level
"expression": "<Expression>", // Override rule expression
"enabled": "false" // Disable this rule
}
}
}Configure Severity Levels
When the severity is not provided it will be warning by default. Other available values for severity are error and note. Configure the severity per rule as shown below:
{
"rules": {
"FlowDescription": {
"severity": "error"
},
"UnusedVariable": {
"severity": "note"
}
}
}Overwrite Expressions
Some rules have an expression to configure, such as the expression, that will overwrite default values. These can be configured in the same way as severity as shown in the following example.
{
"rules": {
"APIVersion": {
"expression": "===58" // comparison operator
},
"FlowName": {
"expression": "[A-Za-z0-9]" // regular expression
}
}
}Define Exceptions
Defining exceptions allows you to exclude specific scenarios from rule enforcement. Exceptions can be specified at the flow, rule, or result level to provide fine-grained control. Below is a breakdown of the available attributes of exception configuration:
{
"exceptions": {
"<FlowName>": {
"<RuleName>": [
"<ResultName>", // Suppress a result
"*", // Wildcard to suppress all results
...
]
},
...
}
}Example
{
"exceptions": {
"MyFlow": {
"HardcodedId": ["Old_Lookup_1"]
"MissingNullHandler": ["*"],
}
}
}Scan Modes
Beta Mode
New rules are introduced in Beta mode before being added to the default ruleset. To include current Beta rules, enable the optional betamode parameter in your configuration:
{
"betaMode": true
}Rule Mode
By default, Lightning Flow Scanner runs all default rules and merges any custom configurations you provide. This means you can override specific rules without having to list every rule to be executed. If instead, you want to run only the rules you explicitly specify, use "ruleMode": "isolated":
{
"ruleMode": "isolated"
}Installation
sf plugins install lightning-flow-scannerOR
npm install -g lightning-flow-scannerDevelopment
This project optionally uses Volta to guarantee the exact same Node.js and tool versions for every contributor. Install Volta with:
MacOs/Linux:
curl https://get.volta.sh | bashWindows:
winget install Volta.VoltaVolta will automatically install and lock the tool versions defined in
package.json.
Clone the repository
git clone https://github.com/Flow-Scanner/lightning-flow-scanner.gitInstall dependencies:
pnpm installCompile:
pnpm run build:cliRun tests:
pnpm test:cliLinking the Salesforce CLI module locally(Optional):
To link the module, run:
sf plugins link packages/cli
