SfSkills Domains Docs GitHub

Home / flow / flow-element-naming-conventions

flow-element-naming-conventions

Canonical naming conventions for Flow elements (Get_/Update_/Decision_/Loop_/Assignment_), resource variables (var/coll/map/formula/choice/constant/stage/screen), Decision branch outcomes, Stage/Step labels in Orchestrations, Subflow input/output contracts, and fault-path target names. NOT for object or field API naming (use admin/object-creation-and-design) or flow portfolio retirement — use flow/flow-governance.

Open the skill folder on GitHub


Flow Element Naming Conventions

Activate when designing a new Flow, auditing an existing one for readability, or migrating a Process Builder / Workflow Rule (which leaves auto-generated element names like myDecision_4). This is the canonical reference cited by agents/flow-builder/AGENT.md Step 3 (element decomposition), agents/flow-analyzer/AGENT.md (audit signal), and agents/flow-orchestrator-designer/AGENT.md (stage/step naming).


Before Starting

Gather this context before working on anything in this domain:


Questions to Ask Before Configuring

Ask these before renaming anything; the answers decide whether a rename is a cosmetic edit or a contract break, and they set the exit-code contract for scripts/check_flow_element_naming_conventions.py.

AskWhy it mattersWhat a good answer adds
"Is there an existing house prefix table, or do we adopt this skill's?"The checker encodes this skill's tables literally — E-VAR-PREFIX on the resource tokens, W-VERB-PREFIX on the element verbs. A different house table means every conforming flow in the org lints dirtyOne prefix table the checker is pointed at, plus the list of flows expected to fail it on day one
"Are any of these flows packaged, installed in subscriber orgs, or called as a subflow by a parent?"Gotcha 1 / Gotcha 2 — the rename saves with no warning and fails at runtime in the caller; subscribers cannot edit your flow but their parents still call it by API nameA rename-risk class (high / medium / low) per element and a version-bump plan for the high ones
"Which elements are auto-named today — Get_Records_3, myDecision_2_A1?"E-AUTONAME is an ERROR, and Gotcha 5 says the Process Builder converter emits these by default and offers no rename passThe real size of the rename pass, before someone scopes it as "cleanup later"
"Is --strict the CI rule, or are WARNs advisory?"Without --strict the checker exits 0 on every house-style finding; with it, W-VERB-PREFIX, W-IO-PREFIX, W-COLL-SHAPE and W-FAULT-TARGET all break the buildA decided exit-code contract, so the pipeline agrees with the review standard instead of contradicting it
"Who owns fault-target naming, and does it match the org's error-logging skeleton?"Pattern 5 and W-FAULT-TARGET expect one target per parent element (LogFault_<Parent>); an org standardised on a single shared handler will WARN on every fault connectorWhether each WARN is a defect to fix or a documented exception, decided once rather than per pull request
"How do collections get named — plural noun after coll, or a List / s suffix?"W-COLL-SHAPE fires twice: on isCollection variables missing the coll prefix, and on a coll name whose noun reads singularA deterministic rule for the collection check instead of reviewer judgement on collCase vs collCases
"Are Labels throwaway here, or does anything downstream read them?"This skill treats the Label as throwaway and the API Name as the contract, but E-LABEL-DEFAULT and E-LABEL-DUP are ERRORs, and I-LABEL-ECHO fires when a label just restates the API nameWhether labels get authored content (documentation generators, fault triage) or only have to be unique and non-default

What a proper configuration adds over just renaming elements: fault emails and metadata diffs name the business step that failed, the public subflow surface is versioned rather than silently broken, and the naming rule is enforced by a checker in CI instead of relitigated in every review.


Core Concepts

Concept 1 — VerbObject element naming

Every Flow element is a verb acting on a noun. The API Name encodes that:

<Verb>_<Object>[_<Qualifier>]

The verb maps to the element type (Get, Update, Create, Delete, Decision, Loop, Assignment, Screen, Action, Subflow). The noun is the primary record or domain concept. The qualifier disambiguates when more than one element of the same type acts on the same noun in the same flow.

Why this matters: a fault email reads Element "Get_Records_3" failed. The on-call admin has to open the flow, find element 3, and reverse-engineer what it was doing. With Get_OpenCasesByOwner, the email is self-describing.

Concept 2 — Resource prefix discipline

Flow resource variables are typed, but the type is invisible at the call site (e.g. inside a formula, inside an Assignment). Encode the type in the API Name:

PrefixResource typeExample
varSingle-value variablevarAccountId, varCustomerName
collCollection variable (List)collOpenCases, collContactsToInsert
mapApex-defined / map-shaped variablemapAccountById, mapErrorsByRecordId
formulaFormula resourceformulaFullName, formulaIsHighValue
choiceChoice / Picklist Choice resourcechoiceTaskType, choiceCountryList
constantConstantconstantMaxRetries, constantApiVersion
stageStage (legacy stages or Orchestration stage label)stage_LegalReview, stage_FinanceApproval
screenScreen-level variablescreenInputContactInfo
decisionOutcomeOutcome label inside a Decision (when needed in formulas)decisionOutcome_HasActiveContract

Type-disambiguation: when two variables represent the same logical thing in different shapes, encode the shape in the suffix too.

varOpportunityId          // primitive ID
varOpportunityIdString    // explicitly the string form, used inside a formula
collOpportunityIds        // a collection of IDs
mapOpportunityById        // map keyed by ID

Explicit > clever. The reader six months later will thank you.

Concept 3 — API Name is immutable in the contract sense

Once a Flow is deployed and referenced, the API Names of its public surface (Flow API name itself, Subflow input/output variables, Choice values bound to picklists) are part of the contract. Renaming them does NOT cause a save-time validation error — Salesforce will let you save the rename and only blow up at runtime in the parent flow that referenced the old name.

This is the single most expensive naming mistake. Treat the public contract as you would treat a public API method signature: name it deliberately the first time, and bump the Flow version (per flow-versioning-strategy) if you must rename.


Common Patterns

Pattern 1 — VerbObject Element Name

When to use: every element in every flow.

How it works: API Name = <Verb>_<Object>[_<Qualifier>]. Label may be more human-readable ("Get open cases owned by current user") but the API Name stays canonical.

Element type: Get Records
API Name:     Get_OpenCasesByOwner
Label:        Get open cases owned by current user

Element type: Update Records
API Name:     Update_OpportunityStageToClosedWon
Label:        Update opportunity stage → Closed Won

Why not the alternative: Get_Records_1, Update_2, Decision_3 (Salesforce defaults) carry zero information. Fault emails become unreadable, Git diffs become noise, and every audit takes 4× longer.

Pattern 2 — Resource Type Prefix

When to use: every variable, formula, constant, and choice resource you create.

How it works: prefix the API Name with the type token (var, coll, map, formula, choice, constant). Suffix with the noun and (optionally) the shape.

varAccountId            (single record ID)
collOpenCases           (List<Case>)
mapAccountById          (Map<Id, Account>)
formulaFullName         (Formula returning Text)
constantMaxRetries      (Constant Number)
choiceTaskType          (Choice resource)

Why not the alternative: without the prefix, a formula that says {!AccountId} is ambiguous — is it a single ID or a collection? Authors then add casts or duplicate variables to disambiguate, and the flow turns into spaghetti.

Pattern 3 — Default Branch Naming

When to use: every Decision element. Salesforce requires a Default outcome but lets you leave its name blank — never do this.

How it works:

Decision_HasActiveContract
  ├── Outcome:  HasActiveContract           (condition: Account.Active_Contract__c = TRUE)
  └── Default:  NoActiveContract_Default    (no rule — fires when nothing above matched)

Why not the alternative: unnamed default outcomes show up as myDecision.outcome2 in fault diagnostics and as a blank cell in the Flow XML — and a future editor has to re-read every other outcome to figure out what the default is supposed to catch.

Pattern 4 — Subflow Input/Output Contract Naming

When to use: any Subflow that is Available for use as a subflow (i.e., publicly callable).

How it works: treat input/output variable API Names as a published API. Name them once, document them in the Flow's Description, and bump the version on rename.

Subflow:       Account_RollupChildContactsCount
  Input:       inputAccountId           (Available for input,  Text)
  Input:       inputContactStatusFilter (Available for input,  Text, default 'Active')
  Output:      outputContactCount       (Available for output, Number)
  Output:      outputLastContactDate    (Available for output, DateTime)

Use the input / output prefix to make the direction obvious to the parent-flow author. Document the contract at the top of the Flow Description so changes are visible in metadata diffs.

Why not the alternative: silently renaming inputAccountId → inputAcctId saves cleanly in the subflow but breaks every parent flow at runtime with The flow couldn't find a referenced variable. See references/gotchas.md Gotcha 2.

Pattern 5 — Fault-Path Target Naming

When to use: every fault connector that routes to a logging or alerting sub-path.

How it works: name the fault-path target after the parent element so the visual diagram shows the route clearly:

Element:  Update_OpportunityStageToClosedWon
  fault → LogFault_Update_OpportunityStageToClosedWon
            └── Create Records: Integration_Log__c

Why not the alternative: generic names like LogError, FaultLogger, Handle_Error_1 re-converge every fault path into a blob. When two faults fire in the same interview, you can't tell which originated where. See flow-error-monitoring for the broader fault-path skeleton.


Decision Guidance

Element / Resource TypeNaming PatternExample
Get RecordsGet_<Object>[_<Filter>]Get_OpenCasesByOwner
Update RecordsUpdate_<Object>_<PostCondition>Update_OpportunityStageToClosedWon
Create RecordsCreate_<Object>[_<Qualifier>]Create_ChildAccount
Delete RecordsDelete_<Object>[_<Qualifier>]Delete_StaleTasks
DecisionDecision_<Question> (yes/no framed)Decision_HasActiveContract
Decision Outcome<AffirmativeCondition> or Default / NoMatchHasActiveContract, NoActiveContract_Default
LoopLoop_Over<Collection>Loop_OverContacts
AssignmentAssignment_<Verb><Object>Assignment_AccumulateTaskList
ScreenScreen_<PurposeOrStep>Screen_CollectShippingAddress
Action / Apex ActionAction_<VerbObject>Action_SendDocuSignEnvelope
Subflow CallSubflow_<CalledFlowName>Subflow_Account_RollupChildContactsCount
Variable (single)var<Noun>[<ShapeSuffix>]varAccountId, varAccountIdString
Collection variablecoll<NounPlural>collOpenCases, collContactsToInsert
Map / Apex-defined mapmap<Noun>By<Key>mapAccountById
Formulaformula<Noun>formulaFullName
Constantconstant<Noun>constantMaxRetries
Choicechoice<Noun>choiceTaskType
Orchestration StageStage_<BusinessProcessName>Stage_LegalReview
Orchestration StepStep_<Stage>_<Action>Step_LegalReview_AssignToCounsel
Fault target elementLogFault_<ParentElementName>LogFault_Update_OpportunityStageToClosedWon

Known inconsistency: the at-bar sibling skills flow/record-triggered-flow-patterns and flow/subflows-and-reusability ship metadata examples using Classify_* / Set_* element names, a shared Log_Archive_Fault target, and in/out variable prefixes, all of which this table grades as WARN under scripts/check_flow_element_naming_conventions.py (W-VERB-PREFIX, W-FAULT-TARGET, W-IO-PREFIX) — the house rule is undecided, which is why those codes are WARN and not ERROR.


  1. Inventory current names. Pull the Flow XML (sf project retrieve start --metadata Flow:<FlowName>) and grep for <name> values inside <decisions>, <recordLookups>, <recordUpdates>, <assignments>, <loops>, <variables>. List every element whose API Name does not match the pattern table above.
  2. Classify the rename risk. For each non-conforming name, mark whether it is referenced externally:
    • Subflow input/output variable → high risk (parent flows will break at runtime).
    • Choice variable bound to a Picklist field → medium risk (re-bind required after rename).
    • Internal element with no formula reference → low risk (safe to rename).
  3. Apply names from the Decision Guidance table. Use the canonical verb + noun + qualifier shape. Keep API Name <= 80 chars; trim qualifier first if needed.
  4. Rename Decision outcomes. Replace bare Yes / No with affirmative condition names. Name every Default outcome explicitly (Default, NoMatch, or <NegativeCondition>_Default).
  5. For Subflows: if you must rename a public input/output, bump the Flow version per flow-versioning-strategy and update every parent Subflow call. Do NOT rely on save-time validation to catch missed callers — it won't.
  6. For Process Builder migrations: auto-generated names like myWaitEvent_4, myDecision_2 are red flags. Plan a rename pass as part of the migration, not "later" — see process-builder-to-flow-migration.
  7. Re-deploy and verify. Run the flow's tests (per flow-testing) and check that fault paths still route to the correct LogFault_<...> targets. Confirm metadata diff shows only the rename, not unintended structural changes.

Review Checklist


Salesforce-Specific Gotchas

  1. API Name is effectively immutable post-deployment. Salesforce permits the rename in Flow Builder, but every Subflow caller, formula reference, and fault path that referenced the old name will fail at runtime — there is no save-time validation across flow boundaries. Treat public surfaces (Subflow inputs/outputs) as a published contract.
  2. Max 80 characters for API Names. Long verb-object-qualifier names get silently truncated by tools that ingest Flow XML. Aim for <= 60 chars in practice.
  3. Spaces and special chars are auto-replaced with underscores. Typing Get Open Cases as the API Name yields Get_Open_Cases — but the Label keeps the spaces. Don't fight the platform; type underscores from the start so the API Name and your intent stay aligned.
  4. Renamed elements break formulas at runtime, not save time. A formula resource referencing {!Get_Records_3.Id} will save fine after you rename Get_Records_3 to Get_OpenCases, but it will throw Couldn't find an Element at the next interview. There is no global rename tool — you must update every formula manually.
  5. Process Builder → Flow migrations inherit ugly auto-generated names like myWaitEvent_4, myDecision_2, myRule_1_A1. The migration tool does not rename these. If you skip the rename pass, the resulting flow is harder to maintain than the Process Builder it replaced. Bake the rename into the migration plan.
  6. Reserved words silently shadow built-ins. Naming a variable Id or null causes formulas to behave unexpectedly. Salesforce will sometimes refuse to save and sometimes save and fail at runtime — never rely on the save-time check.
  7. Decision outcome order matters when names are weak. If two outcomes are both named Yes, the first one matched wins, and a refactor that re-orders outcomes silently changes routing. Strong, distinct outcome names eliminate this class of bug.

Output Artifacts

ArtifactDescription
Renamed Flow XMLThe Flow with element + variable API Names normalized to the canonical pattern
Decision outcome rename mapOld name → new name, including explicit Default names
Subflow contract documentInputs / outputs with API Name + Type + Description, ready to paste into the Flow Description field
Audit tableNon-conforming element names + proposed replacement + rename risk class (high / medium / low)
Migration cleanup list (PB→Flow)List of myWaitEvent_<n> / myDecision_<n> style names with target replacements

Reference Files

FileRead it when
references/examples.mdYou want the before/after narrative — the name a practitioner shipped first, what it cost, and the corrected shape
references/gotchas.mdA rename saved cleanly and something broke anyway: cross-flow contracts, auto-underscore substitution, reserved words, the 80-char cap
references/llm-anti-patterns.mdYou are reviewing names an AI assistant produced, or self-checking your own output before a pull request
references/well-architected.mdYou need the Operational Excellence framing, the tradeoffs, or the source behind a claim in this skill
references/metadata-examples.mdYou want a complete, deployable *.flow-meta.xml that already conforms end to end, plus a negative fixture and the checker output for both
templates/flow-element-naming-conventions-template.mdYou are recording the rename decision — current names, proposed names, rename-risk class — for review
scripts/check_flow_element_naming_conventions.pyBefore every deploy. --manifest-dir <source tree>; 22 rule codes, exits 1 on any ERROR, and on WARNs too under --strict


Official Sources Used

Package files