Salesforce Flow Interview Questions 2026 — Complete Guide with Flow Types, Debugging, Fault Handling & Apex vs Flow Explained
Salesforce Flow Interview Questions — Complete Guide 2026
Flow Types · Builder · Elements · Resources · Debug · Fault Handling · Recursion · Apex vs Flow · Best Practices — All Explained for Interviews
| Flow Type | Trigger | Has UI? | Use Case |
|---|---|---|---|
| Screen Flow | User clicks button | ✅ Yes | Guided wizards, forms |
| Record-Triggered Flow | Record create/update/delete | ❌ No | Auto-updates, notifications |
| Schedule-Triggered Flow | Date + Time + Criteria | ❌ No | Nightly jobs, reminders |
| Autolaunched Flow | Apex / Subflow / REST API | ❌ No | Reusable background logic |
| Platform Event Flow | Platform Event received | ❌ No | Real-time event-driven integration |
- ✅Create / Update / Delete records declaratively — no code
- ✅Send emails, post Chatter, send custom notifications, submit approvals
- ✅Call Apex via
@InvocableMethodfor heavy lifting - ✅Show UI Screen elements — multi-step guided wizards
- ❌Cannot do dynamic SOQL with runtime-built WHERE clauses
- ❌Cannot process 50,000+ records — need Batch Apex for that
At XYZ Company, a Record-Triggered Flow fires when an Order is created and auto-assigns freight charges based on territory — replacing a manual email process. Result: 90% reduction in processing time, ₹13–15L annual savings, zero manual effort.
- 🔥Workflow Rules and Process Builder are retired — Flow is the only declarative automation tool going forward
- 💡Official Salesforce stance: "Flow First, Apex Second"
- 💡Flow respects governor limits — same Apex limits apply
- 💡Record-Triggered Flows can run Before Save (zero DML) or After Save (full power)
| Flow Type | Default Context | Pause/Resume? | Called From |
|---|---|---|---|
| Screen Flow | User Mode | ✅ Yes | Button / App Builder / URL |
| Record-Triggered Flow | System Without Sharing | ❌ No | Record save event |
| Schedule-Triggered Flow | System Without Sharing | ❌ No | Date + Time + Criteria |
| Autolaunched Flow | System Without Sharing | ❌ No | Apex / Subflow / REST API |
| Platform Event Flow | System Without Sharing | ❌ No | Platform Event published |
- ✅Screen Flow — only type with user interaction. Supports Pause/Resume. Cannot be called as Subflow.
- ✅Record-Triggered — Before Save or After Save. Most common type in production orgs.
- ✅Schedule-Triggered — Daily, Weekly, Once only. No native hourly option.
- ✅Autolaunched — no UI. Callable from Apex via
Flow.Interview. Primary = Subflow logic. - ❌Cannot call Screen Flow as a Subflow — must be Autolaunched type
| State | Can Delete? | Runs? | Can Reactivate? |
|---|---|---|---|
| Active | ❌ No — deactivate first | ✅ Yes | Already active |
| Inactive | ✅ Yes | ❌ No | ✅ Yes |
| Obsolete (old versions) | ✅ Yes | ❌ No | ❌ No |
| Invalid | ✅ Yes | ❌ No | ❌ No |
- ✅Can delete Inactive and Obsolete versions to clean up org
- ❌Cannot delete Active Flow — must deactivate first
- ❌Deleted Flows do NOT go to Recycle Bin — permanently gone
- ⚠️Only backup: Export Flow as XML from Setup → Flows → Export
- ⚠️If Flow is referenced by a button or Apex — deletion breaks those references
- 🔥Must deactivate before deleting — cannot delete Active flow directly
- 🔥Deleted Flows are NOT in Recycle Bin — permanent and irreversible
- 💡Always export XML before major changes — Setup → Flows → Export
- 💡For enterprise orgs — use Salesforce DX + Git to version control Flow XML metadata
| Element | What It Does | Apex Equivalent |
|---|---|---|
| Get Records | Query records from database | SOQL SELECT |
| Create Records | Insert new records | DML insert |
| Update Records | Update existing records | DML update |
| Delete Records | Delete records | DML delete |
| Decision | Branch logic based on conditions | if / else if / else |
| Loop | Iterate through a collection | for loop |
| Assignment | Set variable values | variable = value |
| Screen | Show UI to user | Visualforce / LWC |
| Apex Action | Call Invocable Method | @InvocableMethod call |
| Subflow | Call another Autolaunched Flow | method call to another class |
| Resource | Purpose | Changes at Runtime? |
|---|---|---|
| Variable | Store single value (Text, Number, Record) | ✅ Yes |
| Collection Variable | Store list of records or values | ✅ Yes |
| Constant | Fixed value — never changes | ❌ No |
| Formula | Calculated expression (recalculates on reference) | ✅ Recalculates |
| Text Template | Dynamic email/text body with merge fields | ✅ Yes |
| Stage | Track Screen Flow progress steps | ✅ Yes |
- 🔥NEVER do DML inside a Loop — collect records → one bulk DML after loop ends
- ✅Get Records returns null if no records found — always handle with Decision element after
- ✅Text Templates are underused — perfect for dynamic email bodies with merge fields
| Section | What It Does |
|---|---|
| Toolbox (Left Panel) | All Elements and Resources available to drag onto canvas |
| Canvas (Center) | Visual workspace where elements are connected |
| Start Element | Defines trigger — Record change, Schedule, Screen, Platform Event |
| Properties Panel (Right) | Configure selected element — fields, conditions, values |
| Debug Button | Run Flow step-by-step with test data before activating |
| Activate Button | Makes Flow live in org |
- ✅Create and edit all 5 Flow types from one unified interface
- ✅Debug execution step-by-step with real or test data — no deployment needed
- ✅Manage all versions — see version history, activate/deactivate
- ❌Cannot simulate bulk data — debug runs single record at a time
- ❌No built-in version diff — cannot compare what changed between versions
- ❌Cloud Flow Designer was the OLD retired tool — Flow Builder is the current one
- 🔥Flow Builder is at Setup → Flows
- 💡Cloud Flow Designer is retired — mentioning it shows awareness of platform history
- 💡Elements with errors show in red — cannot save until all errors resolved
- 💡Always debug before activating — production best practice, no exceptions
| Feature | Elements | Resources |
|---|---|---|
| What it is | Action steps on the canvas | Data containers and values |
| Examples | Get Records, Decision, Loop, Screen | Variable, Collection, Formula, Constant |
| Apex Equivalent | Statements and method calls | Variables, constants, expressions |
| Visible on canvas? | ✅ Yes — draggable boxes | ❌ No — defined in Toolbox panel |
| Has connectors? | ✅ Yes — arrows link elements | ❌ No — referenced inside elements |
- 🔥NEVER do DML inside a Loop — collect into Collection Variable inside loop → bulk DML after
- ✅Get Records null handling — always add Decision after Get Records to check if result is null
- ✅Input/Output Variables = how Flows talk to Apex, Screen LWCs, and other Flows
- ✅Formula Resources recalculate every time referenced — Variable stores a fixed point-in-time value
| Debug Option | What It Does | When to Use |
|---|---|---|
| Run as Another User | Simulates Flow execution as a specific user — respects their profile, FLS, sharing | Catching permission and visibility issues |
| Roll Back Changes | Flow runs fully but all DML rolled back at the end | Testing DML flows safely without polluting data |
| Pass Input Variables | Simulate different data scenarios without real test records | Testing conditional logic paths |
- ✅Debug shows variable values at each step — impossible to see in live execution
- ✅Debug shows which Decision path was taken — YES or NO highlighted
- ✅"Run as Another User" catches FLS/sharing issues invisible when debugging as Admin
- ❌Cannot debug with bulk data — runs single record only
- ❌Cannot debug Guest User context — use Experience Cloud site preview instead
At XYZ Company, the Quote Approval Flow worked as Admin but failed for Sales Reps. Debug with "Run as Another User" → found Margin__c field returned null → Sales Rep profile had no Read access on that field. Fixed FLS → issue resolved before going live. Debug saved a production incident.
- 🔥"Run as Another User" is the most underused but most powerful debug feature
- 💡"Roll Back Changes" — safest way to test DML flows without corrupting real data
- 💡Always debug as a non-Admin end user before activating — not just as yourself
- 💡Deliberately pass bad/null data to test Fault Paths fire correctly
| State | Runs? | Can Activate? | Can Delete? |
|---|---|---|---|
| Active | ✅ Yes — live in org | Already active | ❌ Deactivate first |
| Inactive | ❌ No | ✅ Yes | ✅ Yes |
| Obsolete | ❌ No (was active, now replaced) | ❌ No | ✅ Yes |
| Invalid | ❌ No — has errors | ❌ No | ✅ Yes |
- ✅Every Save = new version — V1, V2, V3 — automatic
- ✅Can reactivate any old Inactive version — instant rollback in 30 seconds
- ❌No built-in diff tool — cannot compare what changed between versions
- ❌No commit messages — use Description field to document changes
- ❌No Git branching — use Salesforce DX + Git for enterprise version control
- 🔥Rollback = just reactivate old version — fastest recovery in a production incident
- 💡Keep last 2–3 versions as rollback safety net — delete very old obsolete versions
- 💡For enterprise orgs — Salesforce DX + Git stores Flows as XML metadata for real version control
- 💡Always export XML before major restructuring — Setup → Flows → Export
target: lightning__FlowScreen in the meta XML. 🔥| Type | Examples | Code Needed? |
|---|---|---|
| Standard Flow Components | Text Input, Picklist, Number, Checkbox, File Upload | ❌ No |
| Custom LWC Components | Custom Lookup, Data Table, Signature Pad | ✅ Yes |
| AppExchange Components | Pre-built from Salesforce Labs / ISVs | ❌ No |
- 🔥Set
target: lightning__FlowScreenin meta XML — without this LWC won't appear in Flow Builder - ✅Use
FlowAttributeChangeEventto pass output values from LWC back to Flow - ✅Use
FlowNavigationNextEventto programmatically navigate Flow forward from LWC - ✅Mark output properties with
role="outputOnly"in meta XML - ❌Cannot access Flow variables directly — only via explicit Input/Output properties
At XYZ Company, a customLookup LWC with search-as-you-type was built (standard Flow has no lookup) and embedded in the Quote creation Screen Flow. Output selectedRecordId stored in a Flow variable → passed to Create Records element. Full lookup UX without leaving the Flow framework.
@InvocableMethod on a public static Apex method exposes it to Flow as an Action element. Use @InvocableVariable on inner class properties for input/output fields. 🔗| Parameter | What It Does | Example |
|---|---|---|
label | Name shown in Flow Builder action search | 'Calculate Freight' |
description | Tooltip shown in Flow Builder | 'Calculates freight charge based on territory' |
category | Groups actions in Flow Builder | 'Order Management' |
callout=true | Required if method makes HTTP callouts | callout=true |
- 🔥Method must be
public static— non-negotiable, instance methods not supported - 🔥Input and output must always be
List<>— even for single record operations - ✅
callout=truerequired if Apex makes HTTP callout — otherwise Flow throws runtime error - ❌Cannot use
@futureinside Invocable Method — use Queueable Apex inside instead - ❌Governor limits are shared — Apex called from Flow shares the same transaction SOQL/DML budget
At XYZ Company, the IndiaMART Scheduled Flow calls an @InvocableMethod Apex class that makes the HTTP callout to IndiaMART REST API. Flow handles the schedule and orchestration — Apex handles the actual API call and JSON parsing. Flow does the WHAT. Apex does the HOW.
| Rule | Detail |
|---|---|
| Child Flow Type | Must be Autolaunched Flow — cannot call Screen Flow as Subflow |
| Child Flow Status | Must be Active — calling Inactive = runtime error |
| Data Exchange | Input Variables (Parent → Child), Output Variables (Child → Parent) |
| Governor Limits | Shared across Parent + all Child Flows in same transaction |
| Circular Calls | ❌ Not allowed — Flow A → Flow B → Flow A = error |
| Nested Subflows | ✅ Supported — Child can call another Subflow |
- ✅Best pattern for reusable logic — change child once, updates all parent Flows
- ✅Parent can call multiple Subflows in sequence or inside a Loop
- ❌Child variables NOT auto-visible in Parent — must explicitly map via Input/Output Variables
- ❌Cannot call Record-Triggered or Scheduled Flows as Subflow — Autolaunched only
At XYZ Company, a Chatter Notification Autolaunched Flow was built once and called from 8 different parent Flows. When notification template changed → updated child Flow once → all 8 parent Flows automatically used the new template. DRY principle applied to Flow.
| Action | What It Does | Key Requirement |
|---|---|---|
| Send Email | Send email using template or custom body | Can use Email Templates or Text Template resource |
| Email Alert | Trigger existing Workflow Email Alert | Alert must exist in Setup → Email Alerts |
| Submit for Approval | Submit record into Approval Process | Approval Process must be Active for that object |
| Post to Chatter | Post message on record or user feed | Chatter must be enabled in org |
| Send Custom Notification | Push notification to bell icon + mobile | Custom Notification Type must be created in Setup first |
| Apex Action | Call @InvocableMethod Apex class | Method must be public static with @InvocableMethod |
| Subflow | Call another Autolaunched Flow | Child Flow must be Active + Autolaunched type |
| Publish Platform Event | Fire a Platform Event for integrations | Platform Event object must exist |
- 🔥Send Email vs Email Alert — Send Email builds body in Flow. Email Alert reuses existing Workflow Email Alert template.
- ✅Custom Notification requires Custom Notification Type created in Setup FIRST — common mistake in interviews
- ✅Submit for Approval from Flow = fully headless — user never has to click Submit button manually
{!$Record} = current/new field values. {!$Record__Prior} = previous/old field values before the change. Flow's equivalent of Trigger.new and Trigger.old. 📌| Feature | {!$Record} | {!$Record__Prior} |
|---|---|---|
| Contains | Current / new field values | Previous / old field values |
| Apex Equivalent | Trigger.new[0] | Trigger.old[0] |
| Available on Create | ✅ Yes | ❌ NULL — nothing existed before |
| Available on Update | ✅ Yes | ✅ Yes |
| Available on Delete | ✅ Yes | ✅ Yes |
| Before Save Flow | ✅ Yes | ✅ Yes |
| After Save Flow | ✅ Yes | ✅ Yes |
- 🔥Entry Condition:
{!$Record.Stage__c} ≠ {!$Record__Prior.Stage__c}— fires ONLY when Stage actually changes - ✅Using
$Record__Priorin Entry Conditions = biggest performance optimization for Record-Triggered Flows - ⚠️
$Record__Prioris NULL on Create — always handle with Decision or trigger on Update only
At XYZ Company, the Order Confirmation Flow entry condition: {!$Record.Status__c} = "Confirmed" AND {!$Record__Prior.Status__c} ≠ "Confirmed" — fires ONLY when Status first becomes Confirmed. Without this, 500+ Chatter posts fired on every bulk Order edit!
| Feature | Fast Field Update (Before Save) | Actions & Related Records (After Save) |
|---|---|---|
| When it runs | Before record committed to DB | After record committed to DB |
| Apex Equivalent | before insert / before update trigger | after insert / after update trigger |
| Update triggering record? | ✅ Via Assignment — ZERO extra DML | ⚠️ Needs Update Records element |
| Update related records? | ❌ No | ✅ Yes |
| Call Apex / Send Email? | ❌ No | ✅ Yes |
| Add Custom Error (block save)? | ✅ Yes | ❌ No — already saved |
| HTTP Callouts? | ❌ No | ✅ Via Async Path |
At XYZ Company: Before Save Flow auto-calculates Freight Charge on Order save (zero DML overhead). After Save Flow submits for Approval, posts Chatter, sends customer email, and syncs to Business Central — all triggered after Order is safely committed to DB.
- 🔥Before Save = fastest option for same-record updates — zero extra DML, always use this first
- 🔥Cannot add Custom Error in After Save — record already committed — too late to block
- 💡Cannot call Apex in Before Save — Salesforce restriction — Before Save is the fast synchronous path
- 💡HTTP Callouts in After Save must go in the Async Path — cannot mix callout + DML in same transaction
| Method | What It Does | Use Case |
|---|---|---|
| Grant Record Access (Action) | Creates Manual Share on a record | Share with specific user/group at runtime |
| Revoke Record Access (Action) | Removes Manual Share from record | Remove access when condition changes |
| Transfer Ownership | Change OwnerId on record | New owner gets full access automatically |
- ✅Can set Access Level — Read Only or Read/Write
- ✅Works with Users, Public Groups, Roles, Role + Subordinates
- ❌OWD must be Private or Public Read Only — if OWD is Public Read/Write, sharing is irrelevant
- ❌Flow creates Manual Shares only — custom RowCause requires Apex Managed Sharing
| Property | Detail |
|---|---|
| Range | 1 to 2000 |
| Lower number | Runs FIRST |
| No order set (default) | Runs LAST — after all numbered Flows |
| Same number on two Flows | Salesforce picks order — unpredictable |
| Where to set | Flow Builder → Start Element → Advanced → Trigger Order |
| Before Save vs After Save | Each has its OWN independent ordering |
- 🔥Use gaps of 10 (10, 20, 30) — not 1, 2, 3 — allows inserting new Flows without renumbering
- ✅Validation Flows first (lowest number) → Calculation Flows → Integration Flows last
- ✅Document Trigger Order in Flow Description field — dependency map for future admins
At XYZ Company, Order Before Save Flows: Order 10 = KYC Validation (catches errors first), Order 20 = Quote Stage Validation, Order 30 = Freight Calculation. Before ordering, Freight was calculated before KYC validation — freight calculated even for invalid orders!
| Feature | Immediate Path | Asynchronous Path |
|---|---|---|
| When it runs | Same transaction as record save | New transaction after original completes |
| HTTP Callouts allowed? | ❌ No (if DML also present) | ✅ Yes — clean transaction |
| Governor Limits | Shared with original transaction | ✅ Fresh limits — new transaction |
| Blocks record save? | ✅ Errors roll back save | ❌ No — record already saved |
| User waits for it? | ✅ Yes | ❌ No — user moves on immediately |
| Apex Equivalent | Synchronous Apex | @future / Queueable Apex |
- ⚡Immediate Path: Update related records, submit approval, post Chatter, time-sensitive operations
- 🔄Async Path: HTTP callouts to external systems, heavy processing needing fresh governor limits
- 🔥HTTP Callout + DML cannot be in same transaction — Async Path is the solution
At XYZ Company: Immediate Path — Submit Approval + Post Chatter (must happen right away). Async Path — Business Central HTTP callout + IndiaMART sync (callout + DML cannot mix, and user doesn't need to wait for BC API response).
| Location | Path | What You See |
|---|---|---|
| Scheduled Jobs (Primary) | Setup → Scheduled Jobs | Next run time, frequency, delete option |
| Paused and Waiting Interviews | Setup → Paused and Waiting Interviews | Queued / paused / stuck Flow interviews |
| Flow Detail Page | Setup → Flows → Click Flow Name | Flow type confirmation, Active status |
- 1️⃣Setup → Flows → Confirm type = "Schedule-Triggered" and Status = "Active"
- 2️⃣Setup → Scheduled Jobs → Confirm job exists with correct frequency and next run time
- 3️⃣Setup → Paused and Waiting Interviews → Check for queued or stuck interviews
- 🔥Active status alone ≠ Flow is scheduled — must check Scheduled Jobs separately
| Issue Type | What Run As Detects |
|---|---|
| FLS Issues | Field not visible to user → Get Records returns null for that field |
| Sharing Issues | User can't see record → Get Records returns 0 records |
| Profile Permission Issues | User can't create records → Create Records element fails |
| Record Type Differences | Different picklist values appear per user's record type |
- 🔥Most underused — most developers only debug as Admin and miss permission issues entirely
- ✅Roll Back Changes works with Run As too — safe to test DML as another user
- ❌Cannot debug as Guest User — use Experience Cloud Site preview for guest flow testing
- ✅Always do at least one debug run as a non-Admin end user before going live
| Frequency | Options Available | Use Case |
|---|---|---|
| Once | Specific Date + Time | One-time data migrations, single run jobs |
| Daily | Start Date + Time | Nightly jobs, daily reports |
| Weekly | Day(s) of week + Time | Monday + Friday reminders, weekly digests |
| Hourly | ❌ NOT available natively | Use Scheduled Apex + Autolaunched Flow workaround |
| Monthly | ❌ NOT available natively | Use Daily with date formula condition |
- ✅Scheduled Apex with cron expression
'0 0 * * * ?'→ calls Autolaunched Flow viaFlow.Interviewevery hour - ✅Platform Event fired every hour from external system → Platform Event-Triggered Flow fires
At XYZ Company, IndiaMART Lead Sync needed hourly execution — Scheduled Flow only offers Daily/Weekly/Once. Solution: Scheduled Apex runs every hour via cron → calls IndiaMART Autolaunched Flow via Flow.Interview. Best of both worlds — Apex scheduling power + Flow logic.
Account acc in Apex). Record Collection Variable = MULTIPLE records as a List (like List<Account> in Apex). 📦| Feature | Record Variable | Record Collection Variable |
|---|---|---|
| Stores | Single sObject record | List of sObject records |
| Apex Equivalent | Account acc | List<Account> accs |
| Get Records → How | First Record Only option | All Records option |
| Loop input | ❌ Cannot loop directly | ✅ Loop iterates through it |
| Loop current item | ✅ Auto-created Record Variable per iteration | ❌ Not applicable |
| Bulk DML | Single record DML | ✅ Bulk DML in one operation |
- 🔥NEVER DML inside a Loop — Assignment add to Collection Variable inside loop → one bulk DML after loop ends
- ✅Get Records "First Record Only" → Record Variable
- ✅Get Records "All Records" → Collection Variable → Feed into Loop
- ✅Current item in Loop = Record Variable (auto-created) → work on it → add to output collection
| Feature | Pause (Screen Flow) | Wait Element (Record-Triggered) |
|---|---|---|
| Initiated by | User — clicks Pause button | System — waits for time/event condition |
| Flow Type | Screen Flow only | Record-Triggered Flow |
| State saved to DB? | ✅ Yes — Setup → Paused Interviews | ✅ Yes — queued interview |
| Who resumes? | Same user who paused | System — when condition met |
| Expiry | 30 days | Configurable |
- ✅Screen Flow only — no other Flow type supports user-initiated Pause
- ❌Guest Users cannot pause — no authenticated user context to save interview to
- ❌DML executed before pause is NOT rolled back — record changes persist even if user never resumes
- 🔥Pause = user-initiated | Wait Element = system-initiated — key distinction for interviews
- ✅Admin can view and delete stuck paused interviews at Setup → Paused and Waiting Interviews
| Method | Flow Type | Audience |
|---|---|---|
| Lightning App Builder | Screen Flow | Internal — embedded on record/app/home page |
| Quick Action / Button | Screen Flow | Internal — on-demand trigger on a record |
| Direct Flow URL | Screen Flow | Internal — shareable link /flow/API_Name |
| Custom Tab | Screen Flow | Internal — standalone navigation item |
| Utility Bar | Screen Flow | Internal — always-on sidebar tool |
| Experience Cloud | Screen Flow | External — customer/partner portal |
| Salesforce Mobile App | Screen Flow | Mobile users / field reps |
| Apex (Flow.Interview) | Autolaunched | Programmatic — from triggers/batch/queueable |
| Subflow Element | Autolaunched | Other Flows — reusable logic modules |
- 🔥User must have "Run Flows" permission on their Profile or Permission Set — without this, no distribution method works
- ✅Experience Cloud = only way to share Screen Flows with external/unauthenticated users
- ✅Utility Bar = best for repeated tools users need without leaving current page
| Mode | Respects FLS? | Respects Sharing? | Default For |
|---|---|---|---|
| System Without Sharing | ❌ Bypassed | ❌ Bypassed | Record-Triggered, Scheduled, Autolaunched Flows |
| System With Sharing | ❌ Bypassed | ✅ Respected | Configure explicitly in Flow Properties |
| User Mode | ✅ Respected | ✅ Respected | Screen Flow (default) |
- 🔥Screen Flow defaults to User Mode — most secure for user-facing flows
- 🔥Record-Triggered defaults to System Without Sharing — sees all records regardless of user
- ✅Configure in Flow Properties → "How to Run the Flow" section
- ❌Running context does NOT auto-inherit to Subflows — configure each Flow independently
- ❌Apex called from Flow has its own sharing model — Flow context doesn't transfer to Apex
| Feature | Flow (Definition) | Flow Interview (Instance) |
|---|---|---|
| What it is | Blueprint / Template | Actual running execution |
| Created by | Admin / Developer in Flow Builder | Salesforce at runtime when triggered |
| Contains | Elements, Resources, Logic structure | Runtime variable values, current position |
| Apex Equivalent | Apex Class definition | Apex Class instance (new MyClass()) |
| Visible in Setup | Setup → Flows | Setup → Paused and Waiting Interviews |
- ✅Created: User triggers / Record saves / Schedule fires
- ✅Paused: User paused Screen Flow — saved to DB — visible in Paused Interviews
- ✅Finished: Flow reached End element — interview destroyed from memory
- 🔥Always set a meaningful Interview Label:
"Order {!OrderNumber} — {!$Flow.CurrentDateTime}"— helps Admin find stuck interviews - ❌Paused interviews expire after 30 days — inform users to resume before expiry
| Flow Scenario | Same Transaction? | New Transaction? |
|---|---|---|
| Before Save Flow | ✅ Same as record save | — |
| After Save Flow (Immediate Path) | ✅ Same as record save | — |
| After Save Flow (Async Path) | — | ✅ New — after original completes |
| Scheduled Flow run | — | ✅ New — independent transaction |
| Subflow called from Flow | ✅ Same as parent Flow | — |
- 🔥All automation shares governor limits — Flow + Apex + WFR all share the same SOQL/DML budget
- ✅Async Path = new transaction → fresh limits + independent rollback — biggest advantage
- ✅Fault Path prevents rollback — catches errors so transaction can still commit gracefully
- ❌Flow has no Savepoints — error = entire transaction rolls back (unless Fault Path catches it)
- 🔥DML inside Loop = transaction killer — hits DML limits fast — always collect + bulk DML
| Connector Type | Style | Purpose |
|---|---|---|
| Regular Connector | Solid arrow | Standard next step — go here after this element |
| Outcome Connector | Labeled arrow | Decision element paths — YES / NO / Default |
| Fault Connector | Red dashed arrow | Error path — fires when element fails |
| Next Connector (Loop) | Loop arrow back | Returns to Loop element for next iteration |
| After Last Connector | Exit arrow | Exits Loop after all iterations complete |
| Go To Connector | Jump arrow | Skip to any element — merge multiple paths |
- 🔥No Default Outcome on Decision → Flow has no path for unexpected values → runtime error
- 🔥No Fault Connector on DML → DML failure → unhandled error → entire transaction rolls back
- 🔥Missing After Last on Loop → Flow doesn't know where to go after last iteration → error
- ✅Go To connector — newer feature — merges paths to same element without duplicating elements
| Option | UX | Search-as-you-type | Code Needed? | Limit |
|---|---|---|---|---|
| Record Choice Set | ⚠️ Basic dropdown | ❌ No | ❌ No | 200 records max |
| Custom LWC Lookup | 🔥 Full lookup UX | ✅ Yes | ✅ Yes | None |
| AppExchange Component | ✅ Good | ✅ Yes | ❌ No | Third party |
- 🔥Set
target: lightning__FlowScreenin meta XML — mandatory to appear in Flow Builder - ✅Use
FlowAttributeChangeEventto pass selected record ID back to Flow - ✅Mark output properties with
role="outputOnly"in meta XML - ❌Record Choice Set limit — 200 records max, no search-as-you-type — not suitable for large datasets
| Element | Fault Path Available? |
|---|---|
| Create Records | ✅ Yes |
| Update Records | ✅ Yes |
| Delete Records | ✅ Yes |
| Apex Action | ✅ Yes |
| Subflow | ✅ Yes |
| Send Email / Custom Notification | ✅ Yes |
| Decision / Assignment / Loop | ❌ These cannot fail |
| Get Records | ❌ Returns null — not an error — handle with Decision |
- ✅Pattern 1 — Log + Notify: Fault → Assignment stores
{!$Flow.FaultMessage}→ CreateFlow_Error_Log__crecord → Send email to admin - ✅Pattern 2 — User-Friendly Error (Screen Flow): Fault → Assignment → Screen element with friendly message + retry option
- ❌Get Records has NO Fault Path — returns null if no records found → handle with Decision element instead
At XYZ Company, the IndiaMART Scheduled Flow hit API timeout at 11 PM. Fault Path caught it: stored {!$Flow.FaultMessage} → created Flow_Error_Log__c → sent admin email. Flow ended gracefully, error logged, next hourly run attempted automatically. Zero data corruption.
| Step | What to Do | Key Config |
|---|---|---|
| Step 1 | Create Text Variable | API Name: NewRecordId | Available for Output: ✅ |
| Step 2 | Configure Create Records element | Select "Manually assign variables (advanced)" → map ID to {!NewRecordId} |
| Step 3 | Add Navigate Action after Create Records | Type: Record | Record ID: {!NewRecordId} |
| Step 4 | User lands on new record page | Browser navigates to newly created record ✅ |
- 🔥Must select "Manually assign variables (advanced)" — without this, the ID is not captured
- ✅Navigate Action supports: Record, List View, App Page, Web Page
- ✅Always add Fault Path on Create Records — if creation fails, Navigate never fires
- ❌Flow Finish Behavior in Properties cannot use dynamic runtime IDs — only works for static targets
| Feature | Record Lookup (Old) | Fast Lookup (Old) | Get Records (Current) |
|---|---|---|---|
| Status | ⛔ Retired | ⛔ Retired (merged in) | ✅ Active |
| Returns | Individual field values → separate variables | Entire sObject record | Record Variable or Collection |
| Performance | 🐢 Slow and verbose | ⚡ Fast | ⚡ Fast (uses Fast Lookup approach) |
| Multiple records? | ❌ First only | ✅ Yes | ✅ Choose First Record or All Records |
- ❌Record Lookup — one separate variable per field → verbose, hard to maintain, slow
- ✅Fast Lookup — entire record stored in one variable → access any field at any time
- ✅Modern Get Records = Fast Lookup approach — one record or collection variable holds complete record(s)
@InvocableMethod on the Apex method exposes it to Flow. @InvocableVariable on inner class properties defines the input/output fields visible in Flow Builder. These two together = full Apex-Flow integration. 🔗| Annotation | Applied On | Key Requirement |
|---|---|---|
@InvocableMethod | Apex method | Must be public static — instance methods not supported |
@InvocableVariable | Inner class properties | Must be public — defines fields shown in Flow Builder |
- 🔥Method must be
public static— most common mistake - 🔥Always use
List<>for both input and output — even for single value — makes it bulk-safe - ✅Add
callout=trueto@InvocableMethodif method makes HTTP callouts - ✅Add
required=trueto@InvocableVariableto make Flow input mandatory - ❌Cannot use
@futureinside — use Queueable Apex for async within Invocable Methods - ✅Test class still required — Invocable Methods need @isTest coverage like any Apex
| Component | Multi-select? | Required Toggle | Best For |
|---|---|---|---|
| Picklist | ❌ Single only | ✅ Toggle OFF | Small value sets |
| Multi-Select Picklist | ✅ Yes | ✅ Toggle OFF | Multiple selections |
| Radio Buttons | ❌ Single only | ✅ Toggle OFF | 3–5 visible options |
| Record Choice Set | ❌ Single only | ✅ Toggle OFF | Records as dropdown (200 limit) |
- 🔥Always add "-- None --" as first Choice with empty value — signals field is optional to user
- ✅Use "Picklist from Object Field" option — auto-pulls active picklist values, stays in sync with org
- ✅Handle null output with Decision element:
{!SelectedValue} IS NULL?→ apply default logic - ❌Multi-select picklist output = semicolon-separated string — need Apex to parse if further processing required
| Property | Detail |
|---|---|
| Where to find | Screen Element → Components → Display → Section |
| Column options | 1 Column / 2 Columns / 3 Columns |
| Multiple Sections per Screen | ✅ Yes — mix and match column layouts |
| Responsive behavior | ✅ Auto-collapses to single column on mobile |
| Custom column widths (30/70)? | ❌ No — equal widths only — need Custom LWC |
| Code needed? | ❌ No — pure declarative |
- ✅Use Section component for standard equal-width columns — zero code needed
- ✅Mix layouts: 2-column section + 1-column notes section on same Screen
- ❌Cannot set custom column widths (e.g. 30/70 split) — always equal — need Custom LWC for that
- ✅Section label is optional — leave blank for seamless no-heading layout
{!$Record.Type__c} ≠ {!$Record__Prior.Type__c}. Assignment sets {!$Record.Payment_Date__c} = {!$Flow.CurrentDate}. Zero extra DML! ⚡| Step | Config | Why |
|---|---|---|
| Flow Type | Record-Triggered — Before Save | Updating SAME record — zero extra DML |
| Object | Account | Type field lives on Account |
| Trigger | Created or Updated | Type can also be set on creation |
| Entry Condition | {!$Record.Type__c} ≠ {!$Record__Prior.Type__c} | Fire ONLY when Type actually changes |
| Assignment | {!$Record.Payment_Date__c} = {!$Flow.CurrentDate} | Stamp today's date — Before Save = zero DML |
- 🔥If ALL three Type values set the same thing — skip Decision → use single Assignment directly
- 🔥Use
{!$Flow.CurrentDate}— NOTTODAY()— that's Formula syntax, invalid in Flow Assignment - ✅If different dates per Type value → add Decision branching to different Assignments per value
- ✅Add Default outcome on Decision — handles future picklist values without runtime error
- ✅Use
{!$Flow.CurrentDateTime}if Payment_Date__c is a DateTime field instead of Date
| Method | Code? | Same Screen? | Dynamic Records? | Best For |
|---|---|---|---|---|
| Conditional Visibility | ❌ No | ✅ Yes | ❌ Static values only | Small fixed value sets |
| Two Screens + Get Records | ❌ No | ❌ Two screens needed | ✅ Yes | Record-based dependencies |
| Custom LWC | ✅ Yes | ✅ Yes | ✅ Yes | Complex, large datasets, best UX |
| Native Object Field | ❌ No | ✅ Yes | ✅ Auto from org config | Existing org field dependency |
- ✅Conditional Visibility — separate picklist per parent value shown/hidden based on parent selection — zero code
- ✅Native object field — if dependency configured in Object Manager — Salesforce handles it automatically
- 🔥Custom LWC — reset child when parent changes: fire
FlowAttributeChangeEvent('childField', '') - ✅Disable child until parent selected:
disabled={isChildDisabled}— prevents invalid state
| Benefit | Flow | Apex |
|---|---|---|
| Code required | ❌ No | ✅ Yes |
| Test class required | ❌ No | ✅ Mandatory (75%+ coverage) |
| Deployment needed | ❌ Activate in UI | ✅ Change Set / SFDX / DevOps |
| Who can build/maintain | Admin + Developer | Developer only |
| Business team can modify? | ✅ Admin can change | ❌ Developer bottleneck |
| Visual debugging | ✅ Step-by-step canvas with variable values | ❌ Debug logs only (hard to read) |
| Built-in version control | ✅ Every save = new version | Requires Git / SFDX setup |
| Rollback speed | ✅ Activate old version — 30 seconds | ❌ Redeploy needed |
| UI capability | ✅ Screen Flow — built in | ❌ Needs separate VF/LWC |
At XYZ Company, Freight Charge Automation in Apex = 3 days dev + test + deployment window. Same logic in Flow = 2 hours → activated same day. Admin now maintains territory/freight rules independently — no developer bottleneck. Flow saved 2 days of development + deployment complexity.
| Scenario | Why Apex Wins |
|---|---|
| Process 10,000+ records | Batch Apex chunks 200 records — Flow hits CPU limits |
| Dynamic SOQL at runtime | Object, fields, WHERE clause built dynamically — impossible in Flow |
| Native HTTP Callouts | Apex native — Flow needs Apex wrapper for callouts |
| Partial transaction rollback | Savepoints — Flow is all-or-nothing |
| Hourly / custom scheduling | Cron expressions — Flow only Daily/Weekly/Once |
| Complex JSON parsing | Full JSON deserialize class — Flow cannot parse JSON natively |
| Recursion / algorithms | Recursive methods — Flow cannot recurse |
| Automated CI/CD testing | Test classes with assertions — Flow debug is manual only |
At XYZ Company: Multi-Currency Conversion for 25,000 Orders → Flow attempted → CPU limit at ~2,000 records → switched to Queueable Apex chain. IndiaMART BC Integration → Apex handles HTTP callout, OAuth token refresh, nested JSON parsing — Flow simply cannot do any of this natively.
| # | Category | Best Practice |
|---|---|---|
| 1 | Performance | NEVER do DML inside a Loop — collect → one bulk DML after |
| 2 | Performance | Use Entry Conditions with $Record__Prior — fire only on specific field changes |
| 3 | Performance | Before Save for same-record updates — zero extra DML |
| 4 | Performance | Get Records outside Loops — one SOQL, not one per iteration |
| 5 | Performance | Use Async Path for callouts and heavy external operations |
| 6 | Error Handling | Always add Fault Path on DML elements and Apex Actions |
| 7 | Error Handling | Log errors to custom Flow_Error_Log__c object |
| 8 | Error Handling | Handle null from Get Records with Decision element |
| 9 | Design | One Flow per process — separation of concerns |
| 10 | Design | Use Subflows for reusable logic — DRY principle |
| 11 | Design | Trigger Order with gaps of 10 (10, 20, 30) |
| 12 | Security | Choose correct running context per Flow type |
| 13 | Testing | Always debug as end user (not just Admin) before activating |
| 14 | Naming | Consistent naming: Object_Purpose_FlowType |
| 15 | Naming | Meaningful Interview Label for traceability |
- 🔥Never DML inside Loop = single most important performance rule — say this first
- 🔥Entry Conditions with $Record__Prior = biggest optimization for Record-Triggered Flows
- 🔥Fault Path on EVERY DML + Apex Action = difference between graceful failure and production disaster
- 💡Before Save = zero DML for same-record updates — always preferred over After Save
- 💡Subflows for reusability — change child once, updates everywhere across all parent Flows
| Technique | How It Works | Best For |
|---|---|---|
| Before Save Flow | Assignment only — zero extra DML — no re-trigger possible | Same-record field updates |
| $Record__Prior Entry Conditions | Fire only when specific field changes — not on every update | Most common scenario — use always |
| Boolean Flag Field | Custom checkbox checked after first run — Flow skips if already checked | One-time-per-record processing |
| Static Variable in Apex | Invocable Method tracks processed IDs in static Set per transaction | Complex multi-Flow + Apex scenarios |
| Check Output Field | Entry condition: output field = prior output field (not yet updated) | Prevents re-trigger after Flow updates field |
- 🔥Before Save = recursion-proof by design — zero DML = no re-trigger possible — most elegant solution
- 🔥$Record__Prior entry conditions = primary declarative prevention — must mention this first
- ✅Detect recursion: look for "Maximum trigger depth exceeded" error + repeated
FLOW_STARTin debug logs - ❌Recursion can be cross-object — Flow A updates Record B → Flow B updates Record A → infinite loop
At XYZ Company, the Order INR Conversion After Save Flow had no entry condition → updated INR_Amount__c → Order changed → Flow fired again → infinite loop → CPU limit exceeded on 500 Orders. Fix: Entry condition — {!$Record.Amount__c} ≠ {!$Record__Prior.Amount__c} AND {!$Record.INR_Amount__c} = {!$Record__Prior.INR_Amount__c}. Solved immediately.
- 🔥Before Save = recursion-proof by design — always prefer for same-record updates
- 🔥$Record__Prior entry conditions = most important declarative recursion prevention tool
- 💡Static variable in Apex = most robust — works across combined Flow + Apex trigger scenarios
- 💡"Maximum trigger depth exceeded" = the error message to recognize recursion in production
Practice with real people
Join the free Mock Interview Community — practice with peers, get honest feedback, and walk into your real interview confident.
Join the Community ↗