> ## Documentation Index
> Fetch the complete documentation index at: https://docs.twine.se/llms.txt
> Use this file to discover all available pages before exploring further.

# Ports

> How values enter and leave Data Engine nodes

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`](/data-engine/arithmetic/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`](/data-engine/arithmetic/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.

<Note>
  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.
</Note>

## 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](/platform/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.

<Note>
  Inside a [Flow Engine](/flow-engine) graph, the values flowing between nodes are token [assigns](/flow-engine/concepts/steps-and-assigns) rather than dated properties. The port model described on this page still applies, but the values themselves are different. Data Engine graphs embedded inside Flow Engine nodes (FlowTransform, FlowFilter, FlowSwitch) behave exactly as described here.
</Note>
