# Forward vs Dependency Execution Paths in Ceres Flow: A Complete Guide

> Understand Ceres Flow execution paths. Learn the difference between Forward and Dependency execution in this complete guide to optimize your data flow processing.

- Repository: [AkiKurisu/ceres](https://github.com/akikurisu/ceres)
- Tags: deep-dive
- Published: 2026-02-24

---

**Forward execution follows explicit control flow wiring between nodes, while Dependency execution automatically resolves data dependencies using topological sorting before running any consuming node.**

Ceres Flow, the visual scripting system in the `akikurisu/ceres` repository, provides two distinct execution models that determine how nodes in a graph are evaluated. Understanding the difference between **Forward** and **Dependency** execution paths is essential for building efficient visual scripts that balance imperative control flow with automatic data resolution.

## What Are the Execution Paths in Ceres Flow?

Ceres Flow evaluates graphs using two complementary strategies. The **Forward execution path** processes nodes sequentially according to explicit `exec` port connections that you wire manually. The **Dependency execution path** analyzes input requirements at runtime and automatically executes provider nodes first, regardless of their position in the forward chain.

These paths are not mutually exclusive—a single graph can contain nodes that use both paradigms. The engine handles the coordination through `ExecutionContext`, which either moves to the next wired node (Forward) or resolves data dependencies via cached topological sorts (Dependency).

## Forward Execution Path

### How Forward Execution Works

The Forward path follows the **explicit execution chain** that you wire together using the `exec` output ports of `FlowNode` instances. When a node completes its work, it calls `executionContext.Forward(nextNode)` to advance to the next node in the sequence.

According to the source code in [`Runtime/Flow/Models/Nodes/Core/ExecutableNode.cs`](https://github.com/akikurisu/ceres/blob/main/Runtime/Flow/Models/Nodes/Core/ExecutableNode.cs), nodes that use this path inherit from `ForwardNode` and implement a sequential control flow. The graph walks from node to node exactly as drawn on the canvas, performing **no analysis of data dependencies** during traversal.

### Implementing Forward Nodes

Forward nodes typically handle imperative logic, sequenced actions, loops, and branching. They declare an `exec` output port and manually trigger the next node in the chain.

```csharp
public class FlowNode_Sequence : ForwardNode
{
    [OutputPort(false), CeresLabel("")]
    public NodePort exec;          // explicit forward port

    protected override UniTask Execute(ExecutionContext ctx)
    {
        // Perform work here
        DoWork();
        
        // Move to the next node explicitly
        ctx.Forward(exec.GetT<ExecutableNode>());
        return UniTask.CompletedTask;
    }
}

```

In this pattern, `ctx.Forward(...)` drives the execution flow. The node determines when and where execution continues, giving you precise control over program order.

## Dependency Execution Path

### How Dependency Execution Works

The Dependency path runs **all data-dependency nodes first** before executing any node that consumes their results. When the engine encounters a node requiring specific inputs, it examines the node's input ports, builds a topologically sorted list of provider nodes, and executes that list automatically.

As implemented in [`Runtime/Core/Models/Graph/CeresGraph.cs`](https://github.com/akikurisu/ceres/blob/main/Runtime/Core/Models/Graph/CeresGraph.cs), the system maintains a cached dependency path (`_nodeDependencyPath`) for each node. When execution requires a specific node's data, `ExecutionContext.ExecuteDependencyPath(guid)` retrieves this cached list and runs each dependency in order, guaranteeing that every required value is computed before the requesting node runs.

### Implementing Dependency Functions

Nodes that provide data rather than control flow use the `[ExecutableFunction(ExecuteInDependency = true)]` attribute defined in [`Runtime/Flow/Annotations/ExecutableFunctionAttribute.cs`](https://github.com/akikurisu/ceres/blob/main/Runtime/Flow/Annotations/ExecutableFunctionAttribute.cs). These nodes lack `exec` ports and rely entirely on the engine's data dependency resolution.

```csharp
public class GetPlayerPosition : FlowNode
{
    // No exec port – it’s a data provider
    [OutputPort, CeresLabel("Position")]
    public NodePort output;

    [ExecutableFunction(ExecuteInDependency = true), CeresLabel("Get Player Position")]
    protected override void LocalExecute(ExecutionContext ctx)
    {
        output.SetValue(Player.instance.Position);
    }
}

```

Because `ExecuteInDependency = true`, the graph executes this node automatically before any node that consumes the "Position" value, regardless of forward wiring or canvas position.

### Behind the Scenes: Topological Sorting

The actual dependency resolution occurs in [`Runtime/Flow/Models/ExecutionContext.cs`](https://github.com/akikurisu/ceres/blob/main/Runtime/Flow/Models/ExecutionContext.cs). The `ExecuteDependencyPath` method retrieves the pre-calculated dependency chain and executes each node:

```csharp
private async UniTask ExecuteDependencyPath(string guid, CancellationToken token)
{
    var path = Graph.GetNodeDependencyPath(guid);   // top-sorted list of dependent nodes
    foreach (var idx in path)
    {
        var node = Graph.nodes[idx];
        await node.ExecuteNode(this);               // runs each dependency node
    }
}

```

The `CeresGraph` builds these paths once via topological sort and reuses them for every execution, ensuring optimal performance for data-driven graphs.

## Key Differences Between Forward and Dependency Paths

Understanding when to use each path requires recognizing their fundamental architectural differences:

- **Forward** = *You* dictate the control flow through explicit `exec` port wiring. Nodes visit one-by-one exactly as arranged on the forward-execution line.
- **Dependency** = The engine determines execution order needed to satisfy **data** dependencies, automatically resolving provider nodes through cached topological sorts.

**Forward execution** excels at imperative logic, UI sequences, and branching narratives where order matters more than data relationships. **Dependency execution** optimizes "getter" nodes, pure functions, and data transformations where inputs must be ready before computation begins.

## When to Use Each Execution Path

Use **Forward execution** when building:
- Sequential gameplay events that must happen in a specific order
- Branching dialogue trees or quest logic
- Loop constructs and iterative processes
- Any logic requiring manual control over execution timing

Use **Dependency execution** when building:
- Data provider nodes (e.g., *Get Player Position*, *Read Variable*)
- Pure calculation functions with input dependencies
- Reactive systems where outputs automatically update when inputs change
- Complex mathematical graphs where manual wiring would be error-prone

## Summary

- **Forward execution paths** in Ceres Flow follow explicit `exec` port wiring that you control manually, using `ExecutionContext.Forward()` to advance between nodes.
- **Dependency execution paths** automatically resolve data requirements using topological sorts cached in `CeresGraph._nodeDependencyPath`.
- Nodes inherit from `ForwardNode` for manual control or use `[ExecutableFunction(ExecuteInDependency = true)]` for automatic data resolution.
- The engine coordinates both paths through `ExecutionContext.ExecuteDependencyPath()`, which runs dependency chains before the requesting node executes.
- Choose Forward for imperative control flow and Dependency for data-driven, reactive computation.

## Frequently Asked Questions

### What is the main difference between Forward and Dependency execution in Ceres Flow?

**Forward execution** requires manual wiring through `exec` ports and visits nodes in the exact order you specify on the canvas. **Dependency execution** automatically analyzes input requirements and executes provider nodes first via topological sorting, regardless of their canvas position or forward connections.

### How does Ceres Flow determine which nodes to run first in Dependency mode?

The engine consults the **dependency cache** stored in `CeresGraph` at `_nodeDependencyPath`. When building the graph, Ceres performs a topological sort on data dependencies and stores the result. During execution, `ExecutionContext.ExecuteDependencyPath()` retrieves this cached list and runs each node in dependency order.

### Can a single node use both Forward and Dependency execution paths?

Yes. A node can inherit from `ForwardNode` while also having input ports that trigger Dependency execution. In this case, the engine first resolves all data dependencies automatically, then executes the node's Forward logic, and finally continues along the `exec` output chain you have wired.

### Where is the dependency execution logic implemented in the Ceres source code?

The core logic resides in [`Runtime/Flow/Models/ExecutionContext.cs`](https://github.com/akikurisu/ceres/blob/main/Runtime/Flow/Models/ExecutionContext.cs), specifically within the `ExecuteDependencyPath` method. The topological sorting and caching mechanism is implemented in [`Runtime/Core/Models/Graph/CeresGraph.cs`](https://github.com/akikurisu/ceres/blob/main/Runtime/Core/Models/Graph/CeresGraph.cs) using the `_nodeDependencyPath` dictionary. The attribute that marks functions for Dependency execution is defined in [`Runtime/Flow/Annotations/ExecutableFunctionAttribute.cs`](https://github.com/akikurisu/ceres/blob/main/Runtime/Flow/Annotations/ExecutableFunctionAttribute.cs).