FlowGraphObject vs FlowGraphInstanceObject: Understanding Container Differences in Ceres

The difference between FlowGraphObject and FlowGraphInstanceObject containers is that FlowGraphObject embeds graph data directly within the MonoBehaviour via source-generated code, while FlowGraphInstanceObject references an external FlowGraphAsset to supply the graph data.

Both classes are Unity MonoBehaviours in the akikurisu/ceres repository that expose runtime FlowGraphs, but they implement the IFlowGraphContainer interface through fundamentally different storage mechanisms. Understanding these container patterns is essential for deciding whether to store graph data per-object or share it across multiple instances.

Container Source: Embedded vs External Asset

FlowGraphObject: Self-Generated Container

In Runtime/Flow/FlowGraphObject.cs, the FlowGraphObject class uses source generation to turn the MonoBehaviour itself into an IFlowGraphContainer. The [GenerateFlow(GenerateRuntime = false, GenerateImplementation = true)] attribute (lines 136-144) triggers the generator to create a partial class that stores persistent FlowGraphData as a hidden sub-asset inside the component.

This approach makes each GameObject fully own its graph data. The generated implementation handles serialization automatically, embedding the graph definition directly within the prefab or scene object.

FlowGraphInstanceObject: Asset Reference Container

Conversely, Runtime/Flow/FlowGraphInstanceObject.cs (lines 7-15) defines an explicit container reference:

public class FlowGraphInstanceObject : FlowGraphObjectBase
{
    [SerializeField] internal FlowGraphAsset graphAsset; // External container
    
    // Container calls forwarded to graphAsset
}

Rather than generating container code, this class implements IFlowGraphContainer by delegating all calls to the serialized FlowGraphAsset field. The graph data lives in a separate asset file, allowing multiple components to reference the same graph definition.

Runtime Container Resolution

The FlowGraphObjectBase class determines which container to use at runtime through the GetContainer() method implemented in Runtime/Flow/FlowGraphObject.cs (lines 76-90):

protected IFlowGraphContainer GetContainer()
{
    // Check for external asset reference first
    if (this is FlowGraphInstanceObject instanceObject && instanceObject.graphAsset != null)
    {
        return instanceObject.graphAsset;
    }
    
    // Fall back to self-contained container
    return this as IFlowGraphContainer;
}

This logic ensures that FlowGraphInstanceObject instances return their referenced FlowGraphAsset, while FlowGraphObject instances return themselves as the container.

Implementation Architecture

Source Generation vs Explicit Implementation

FlowGraphObject relies on compile-time code generation:

  • The partial class FlowGraphObject is augmented by the Ceres source generator
  • The generator implements IFlowGraphContainer and IFlowGraphRuntime interfaces automatically
  • Graph data persists as a sub-asset within the MonoBehaviour (visible in Runtime/Flow/Models/FlowGraph.cs interface definitions)

FlowGraphInstanceObject uses runtime composition:

  • Explicitly declares the graphAsset field of type FlowGraphAsset (defined in Runtime/Flow/FlowGraphAsset.cs)
  • No source generation required for container implementation
  • All container interface methods forward to the referenced asset

Data Persistence Locations

  • FlowGraphObject: Stores FlowGraphData inside the component as a hidden serialized object (self-contained)
  • FlowGraphInstanceObject: Stores data in the external FlowGraphAsset file (shared resource)

When to Use Each Container Type

Choose FlowGraphObject when:

  • Each GameObject requires unique graph data
  • You want self-contained prefabs without external dependencies
  • The graph should serialize with the scene or prefab directly

Choose FlowGraphInstanceObject when:

  • Multiple objects must share identical graph logic
  • Memory efficiency is critical (avoid duplicating graph data across instances)
  • You need to update graph logic in one place (the asset) and affect all instances

Summary

  • FlowGraphObject implements a self-container pattern where the MonoBehaviour itself becomes the IFlowGraphContainer through source-generated code, embedding FlowGraphData as a sub-asset
  • FlowGraphInstanceObject implements an external-container pattern that references a FlowGraphAsset to supply graph data, enabling data sharing across multiple GameObjects
  • The GetContainer() method in FlowGraphObjectBase automatically detects which pattern is in use at runtime
  • Use FlowGraphObject for per-object unique graphs and FlowGraphInstanceObject for shared, asset-based graph definitions

Frequently Asked Questions

Can I switch a FlowGraphObject to use an external asset without changing the component type?

No, the container architecture is determined by the class type itself. FlowGraphObject relies on source-generated container implementation that embeds data within the MonoBehaviour, while FlowGraphInstanceObject explicitly implements container forwarding to a FlowGraphAsset field. Migrating between patterns requires changing the component type and manually transferring graph data to a FlowGraphAsset file.

Where is the graph data physically stored in a FlowGraphObject?

According to the source code in Runtime/Flow/FlowGraphObject.cs, the data persists as a hidden sub-asset directly inside the MonoBehaviour component. The source generator creates this embedded storage when processing the GenerateFlow attribute, making the graph data serialize as part of the GameObject or prefab rather than as a separate asset file.

Does modifying a FlowGraphAsset at runtime affect all FlowGraphInstanceObject instances?

Yes, since FlowGraphInstanceObject forwards all IFlowGraphContainer calls to its shared graphAsset reference, any runtime modifications to that asset would propagate to all instances using it. For independent runtime states, you should instantiate unique copies of the graph data or use FlowGraphObject instead, which stores data per-instance.

How does the Ceres source generator know to implement IFlowGraphContainer for FlowGraphObject?

The GenerateFlow attribute applied to the partial class in FlowGraphObject.cs includes the parameters GenerateRuntime = false and GenerateImplementation = true. This configuration signals the Ceres source generator to create the container implementation and embed the graph data within the component, as seen in the generated code linked through the attribute at lines 136-144 of the source file.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →