Introduction
Salesforce Flows and Apex complement each other: Flows enable low-code orchestration and UI, while Apex provides procedural control, complex logic, and integrations. Integrating Apex with Flows lets you combine the ease of Flow Builder with the power of programmatic Apex.
Primary integration patterns
There are two main directions for integration:
- Flow calling Apex (Apex as a Flow Action) — use Invocable Apex.
- Apex calling Flow — launch Flows from Apex using the Flow.Interview API (run autolaunched Flows programmatically).
Flow calling Apex (Invocable Apex)
Use @InvocableMethod (and @InvocableVariable) to expose Apex as an action in Flow Builder. Invocable methods must be static and accept/return a List of a single type — this encourages bulk-safe behavior.
Minimal example — accept simple input and return a simple output:
public with sharing class FlowApexExample {
public class Request {
@InvocableVariable
public Id recordId;
@InvocableVariable
public Integer qty;
}
public class Response {
@InvocableVariable
public Boolean success;
@InvocableVariable
public String message;
}
@InvocableMethod(label='Process Records from Flow')
public static List
List
for (Request r : requests) {
Response res = new Response();
// implement logic (DML, callouts, validations)
res.success = true;
res.message = 'Processed ' + String.valueOf(r.qty);
results.add(res);
}
return results;
}
}
Key points:
- Always accept and return lists to support bulk operations.
- Use wrapper classes with
@InvocableVariablefor named inputs/outputs (Apex-defined data type). - Label the method with
@InvocableMethod(label='...')to make it friendly in Flow Builder.
Complex types & Apex-defined data types
If you need to pass complex objects (multiple fields, nested values), create Apex classes that act as request/response DTOs. Flow will surface the properties annotated with @InvocableVariable so builders can set them.
Apex calling Flow (Flow.Interview)
Apex can start autolaunched Flows programmatically using the Flow.Interview generated class. This is useful when a complex Flow needs to be invoked as part of server-side logic or integration processing.
// Prepare input variables
Map
// Instantiate Flow interview (replace My_Autolaunched_Flow with Flow API name)
Flow.Interview.My_Autolaunched_Flow flowInterview = new Flow.Interview.My_Autolaunched_Flow(inputs);
// Start the flow
flowInterview.start();
// Optionally read output variables
Object outVal = flowInterview.getVariableValue('outputVarName');
Notes:
- The Flow API name becomes a generated inner class in
Flow.Interview. Use the flow’s API name (spaces replaced by underscores). - Provide inputs as a Map<String, Object> keyed by variable API names.
Other integration routes
- Callouts from Flow: Use Apex actions to perform HTTP callouts since Flows can’t make callouts directly (unless you use external services).
- Platform Events: Use Apex to publish events consumed by Record-Triggered Flows (or vice versa).
- REST / SOAP: Expose Apex REST endpoints used by external services and trigger Flows based on incoming data.
Best practices
- Bulkify invocable methods — accept List inputs and perform DML/queries on collections.
- Keep transaction size in mind — Flow + Apex run in same transaction, so governor limits apply.
- Avoid long-running operations inside Flows; move heavy work to Queueable or Batch Apex when necessary.
- Return meaningful error messages; throw exceptions for unrecoverable errors so Flow can surface them to users or admins.
- Write unit tests for invocable Apex and for Apex that invokes Flows. Cover edge cases and bulk scenarios.
- Secure code with sharing, with proper with/without sharing decisions based on business requirements.
Testing and deployment
Unit tests must cover invocable Apex the same as any other Apex class. When testing Flow-Apex interactions, assert both the Apex behavior and the Flow outputs (when invoking flows from Apex, use test setup to create predictable inputs, then verify outputs).
Conclusion
Integrating Apex with Salesforce Flows unlocks powerful hybrid solutions: use Flows for orchestration and UI, and Apex for complex logic, integrations, and performance-sensitive tasks. Prefer Invocable Apex to expose Apex to Flow, and use Flow.Interview when Apex must trigger Flows. Follow bulkification and governor-limit best practices to build reliable, production-ready integrations.








Leave a Reply