Skip to main content
A Data Engine node communicates with the rest of the graph through ports. Every value that enters or leaves a node passes through one. Understanding what ports are, how they relate to each other, and how the engine resolves their values at runtime is the key to building a graph that does what you expect.

Inputs and outputs

Each port has a direction:
  • Input ports receive values from upstream nodes.
  • Output ports produce values that downstream nodes can connect to.
Inputs are listed on the left of the node diagram on each node’s reference page; outputs on the right.

The default input

Most nodes expose a special input port called default_in. It represents the primary value flowing into the node along the main path of the graph. Connecting two nodes default-to-default is the most common way to wire a graph and matches the way data normally flows through it. In addition to default_in, a node can have any number of named input ports for values that are not the main flow but still need to be supplied. For example, the add node has named input ports x and y for the two operands, in addition to its default_in. Named inputs exist because the default input is not always the value a node should operate on. In a branching flow where the graph pivots to calculating something new, named inputs let you draw values in from completely different sources without disrupting the main flow.

Output ports

Unlike inputs, all output ports are peers. There is no special “main” output channel - a port called default_out is just a convention used by nodes that produce a single primary value, and the human-readable label on it can be anything. A node with multiple outputs (such as divide, which exposes default_out, integer_result, and rem) treats them all the same; downstream nodes connect to whichever ones they need.

Resolving input values

When the engine runs a node, each input port needs a value. The rule is straightforward:
Each named input that is not connected falls back to the value on default_in.
Concretely, for the add node with inputs default_in, x, and y:
  • If both x and y are connected, the node adds those two values directly. The default_in value is not used.
  • If only one of x or y is connected, the unconnected one falls back to default_in.
  • If neither x nor y is connected, both fall back to default_in and the node effectively adds the default value to itself.
This is why the reference pages list default_in alongside the named ports even when the named ports cover everything you’d want to feed in: the named ports are how you override the default value flow, not how you replace the default port.
The interaction between default_in and a named port that resolves to it is being refined. In particular, the editor does not yet make it obvious that connecting both default_in and a named input to the same upstream value is redundant rather than additive. This page will be updated as the UX evolves.

Required inputs

A node can declare an input port as required. A required input must have a value at runtime - if it cannot be resolved when the node runs, the graph fails for the entity being processed. Required is a runtime constraint, not just an editor warning. By convention, the default_in port is the one a node marks as required when it has a single mandatory value. A required port that is not the default is a configuration mistake on the node’s part: the resolution rule says any unconnected named input falls back to default_in, so requiring a non-default port has no real meaning - if you want that value to always be present, requiring default_in already covers it.

Allowed types

Each port declares the value types it accepts. The list of accepted types is shown on the port’s reference card; a port that lists Any accepts whatever you connect to it. The Data Engine validates types in two phases:
  • Editor-time validation - structural checks that can be performed without running the graph. The most common case is connecting an output that produces one type to an input that does not accept it. Failures show up in the editor as errors on the offending node or edge.
  • Runtime validation - checks that depend on the actual values flowing through the graph. Some constraints (for example, that a divisor is non-zero, or that two list inputs are the same length) cannot be evaluated until real data is processed. These also surface in the editor as errors on the node, but only after a graph has been executed against an entity.
A graph that is free of editor-time errors can still fail at runtime. Both kinds of validation matter and both should be reviewed before a graph is considered ready.

Dated properties

All values flowing through the Data Engine are dated properties - that is, every value carries the time dimension that Twine’s data model uses for date-tracked data. A node operating on numbers is not actually receiving raw numbers; it is receiving a dated property whose value at any given point in time is a number. This is a deliberate design choice, and it is the main reason the Data Engine exists as a separate engine from the legacy graph engine. Operations like “find the salary that was active on a given date” or “shift every value in this dated property forward by 30 days” are first-class concerns, and the engine handles the time dimension transparently rather than forcing each node to deal with it. The reference page for each node describes how that specific node interacts with the time dimension where it matters.
The Data Engine is being extended into a higher-level Flow Engine for process flow. In a Flow Engine context, the values flowing between nodes are token structs rather than dated properties. This page will be updated to cover that distinction once the Flow Engine is documented.