SfSkills Domains Docs GitHub

Home / flow / flow-apex-defined-types

flow-apex-defined-types

Design and use Apex-Defined Types as Flow variables for structured non-sObject data (HTTP callout payloads, External Service responses, complex configuration). Trigger keywords: apex-defined type, flow variable. NOT for building HTTP Callout Actions themselves, External Services schema, or raw Apex — use flow/flow-external-services.

Open the skill folder on GitHub


Flow Apex-Defined Types

Adoption Signals

When NOT To Use

Contract

An Apex-Defined Type is a data-only Apex class whose fields Flow reflects as variable attributes. The constraints are unusually tight, and almost all of them compile cleanly and fail in the flow at run time — which is the defining property of this domain.

RequirementDetail
Field typesBoolean, Integer, Long, Decimal, Double, Date, DateTime, String — single values and lists of each, plus lists of other supported Apex-defined types
Annotation@AuraEnabled on every field Flow must see
ConstructorA no-argument constructor is required
Inner classesNot supported
Outer class named the same as an inner classNot supported
Class methodsNot supported
Getter methods for fieldsNot supported
List of lists as a fieldNot supported
Referential integrityNot supported — modify or delete a field in the class and the flow fails
// InvoiceLine.cls — top-level, in its own file.
public class InvoiceLine {
    @AuraEnabled public String  productCode;
    @AuraEnabled public Decimal quantity;
    @AuraEnabled public Decimal unitPrice;
    @AuraEnabled public List<String> tags;

    // Required: a no-argument constructor. Declared explicitly so that adding
    // a convenience constructor later does not silently remove it.
    public InvoiceLine() {}
}

Two consequences people miss. There is no Map on the supported type list — model it as List<KeyValue> with KeyValue as its own top-level class. And because inner classes are unsupported, a nested structure is built from separate top-level classes, not from the nested-class shape every Apex developer reaches for first.

When NOT To Use

  1. Identify the smallest shape Flow actually consumes. Do not mirror the

    upstream schema — referential integrity is unsupported, so every exposed field is a name you have committed not to change without a caller inventory.

  2. Write each type as a top-level class in its own file, with @AuraEnabled

    on every field, an explicit no-argument constructor, no methods, and no getters.

  3. Check every field type against the supported list. No Map, no list of

    lists, no sObject fields.

  4. Write two tests: one that JSON round-trips an instance (which also proves

    the no-argument constructor exists), and one that asserts the serialized field-name set, so a rename fails the build rather than the next scheduled batch.

  5. Bind the class as the Flow variable type from the HTTP Callout, External

    Service, or invocable return. For invocables, take and return List<> so the flow can call once with a collection instead of once per record inside a loop.

  6. Treat the field names as a published interface. Adding a field is safe;

    renaming or removing one is a breaking change with no compile-time signal, so inventory the consuming flows first.

Official Sources Used

The full annotated list is in references/well-architected.md.

Dependencies

Package files