> For the complete documentation index, see [llms.txt](https://docs.fortifiedid.se/pipes/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.fortifiedid.se/pipes/configuration.md).

# Configuration

How Pipes is configured at module level and pipe level.

{% hint style="info" %}
**Module name:** `Pipes`
{% endhint %}

The Pipes module is configured in two layers:

* **Module level** controls the overall Pipes runtime, such as namespace, JMX availability, and which pipes should be deployed.
* **Pipe level** controls one individual pipe, including which valves it contains and whether it should use session handling.

In practice, administrators usually configure the module once and then maintain the individual pipes over time as business and integration needs change.

{% tabs %}
{% tab title="Properties" %}

<table><thead><tr><th>Name</th><th>Description</th><th>Default</th><th data-type="checkbox">Mandatory</th></tr></thead><tbody><tr><td><code>namespace</code></td><td>Module namespace used when registering deployed pipes. This affects how pipes are addressed internally at runtime.</td><td><code>pipes</code></td><td>false</td></tr><tr><td><code>jmx_enabled</code></td><td>Enables the JMX management interface for listing, executing, deploying, and undeploying pipes through JMX.</td><td><code>true</code></td><td>false</td></tr><tr><td><code>pipes</code></td><td>List of <a href="#pipe">pipe</a>s to deploy when the module starts.</td><td><code>[]</code></td><td>false</td></tr><tr><td><code>subpipes</code></td><td>List of <a href="/pipes/subpipes.md">subpipe</a>s to register when the module starts.</td><td><code>[]</code></td><td>false</td></tr></tbody></table>
{% endtab %}

{% tab title="Example" %}

```json
{
    "name": "Pipes",
    "enabled": true,
    "config": {
        "namespace": "pipes",
        "jmx_enabled": true,
        "pipes": [
            {
                "id": "pipe01",
                "enabled": true,
                "display_name": "Example pipe",
                "config": {
                    "valves": [
                        {
                            "name": "SessionPut",
                            "enabled": true,
                            "config": {
                                "name": "session-prop01",
                                "value": "{{request.value}}"
                            }
                        }
                    ],
                    "use_session": true
                }
            }
        ]
    }
}
```

{% endtab %}
{% endtabs %}

## Module-level behavior

When the Pipes module starts, it validates the module configuration, creates the valve registry, and deploys all enabled pipes. Disabled pipes remain defined in configuration but are not deployed.

If JMX is enabled, Pipes also starts a JMX management interface. This is useful for administrators who want to inspect available pipes or trigger dynamic deployment and undeployment through operational tooling. JMX is configured for the module as a whole, not per pipe.

### Pipe

A pipe is the executable unit that a caller invokes. Each pipe should represent one coherent process, for example:

* validating and enriching an incoming request
* preparing data for another system
* calling one or more external services
* formatting the result for the caller

Administratively, a pipe is where most day-to-day maintenance happens. That includes enabling or disabling a pipe, naming it clearly, deciding whether it should use sessions, and maintaining the ordered list of valves inside it.

{% tabs %}
{% tab title="Properties" %}

<table><thead><tr><th>Name</th><th>Description</th><th>Default</th><th data-type="checkbox">Mandatory</th></tr></thead><tbody><tr><td><code>id</code></td><td>Unique identifier of the pipe. This is the technical pipe name used when the pipe is invoked.</td><td></td><td>true</td></tr><tr><td><code>enabled</code></td><td>Flag to enable or disable the pipe. A disabled pipe is not deployed.</td><td><code>true</code></td><td>false</td></tr><tr><td><code>display_name</code></td><td>Optional display name used for logging and runtime visibility. If omitted, the pipe <code>id</code> is used.</td><td><code>id</code></td><td>false</td></tr><tr><td><code>config</code></td><td>Pipe configuration object.</td><td><code>{}</code></td><td>false</td></tr><tr><td><code>config.valves</code></td><td>Ordered list of <a href="/pipes/valves.md">valves</a> forming the pipe.</td><td><code>[]</code></td><td>false</td></tr><tr><td><code>config.use_session</code></td><td>Controls whether the pipe should use session handling. If enabled, a new session is created when no session exists, or an existing session is resolved when a session id is provided.</td><td><code>true</code></td><td>false</td></tr><tr><td><code>timeout</code></td><td>Maximum execution time for the pipe in milliseconds. When the timeout elapses, the pipe is cancelled and a timeout exception is returned to the caller. Set to <code>0</code> to disable the pipe-level timeout.</td><td><code>0</code></td><td>false</td></tr></tbody></table>
{% endtab %}

{% tab title="Example" %}

```json
{
    "id": "pipe01",
    "enabled": true,
    "display_name": "Example pipe",
    "config": {
        "use_session": true,
        "valves": [
            {
                "name": "SessionPut",
                "enabled": true,
                "config": {
                    "name": "session-prop01",
                    "value": "{{request.value}}"
                }
            }
        ]
    }
}
```

{% endtab %}
{% endtabs %}

## Pipe design guidance

For administrators, a good pipe is usually:

* focused on one business or integration outcome
* named clearly enough that its purpose is obvious from the configuration
* built from a small number of valves with clear responsibilities
* easy to troubleshoot because the valve order reflects the actual process

If a flow becomes difficult to understand, it is often better to split it into smaller pipes and reuse them with pipe-to-pipe calls instead of continuing to grow one large pipe.

## Valve configuration inside a pipe

Each pipe contains an ordered list of valves in `config.valves`. Valves are executed from top to bottom.

Each valve has its own configuration object, and valves can also be conditionally executed through common valve settings such as `exec_if_expr`. For valve-specific configuration details, see [Valves](/pipes/valves.md).

{% hint style="info" %}
Session handling is enabled by default. Keep it enabled when the pipe needs to read from or write to session data. Disable it only for fully stateless flows where session creation would add no value.
{% endhint %}

## Expression expansion

Most string values in valve configuration support expression expansion. Use `${scope.key}` to resolve a single typed value, or embed expressions inside a larger string.

### Available scopes

#### `request`

The current pipe request. Access individual parameters with `${request.<key>}`.

#### `session`

| Expression            | Description                     |
| --------------------- | ------------------------------- |
| `${session.id}`       | Session identifier              |
| `${session.trace_id}` | Trace identifier                |
| `${session.<key>}`    | Any value stored in the session |

#### `state`

Data accumulated in the current pipe execution. Access fields with `${state.<key>}`.

#### `exports`

AuthN globals. Only available when the pipe is called in an authentication context.

#### `utils`

Utility values evaluated at expansion time. Each reference is resolved when the expression is expanded, so the value always reflects the current moment.

| Expression              | Description                                | Example                          |
| ----------------------- | ------------------------------------------ | -------------------------------- |
| `${utils.now}`          | Current timestamp, UTC, ISO-8601           | `2026-05-05T13:22:07.123456789Z` |
| `${utils.date}`         | Current date, local server time            | `2026-05-05`                     |
| `${utils.date_utc}`     | Current date, UTC                          | `2026-05-05`                     |
| `${utils.time_hms}`     | Current time `HH:mm:ss`, local server time | `15:22:07`                       |
| `${utils.time_hms_utc}` | Current time `HH:mm:ss`, UTC               | `13:22:07`                       |
| `${utils.time_hm}`      | Current time `HH:mm`, local server time    | `15:22`                          |
| `${utils.time_hm_utc}`  | Current time `HH:mm`, UTC                  | `13:22`                          |

#### `system`

Java system properties. Access individual properties with `${system.<key>}`, for example `${system.customer_home}`.

## Timeout

Pipes supports two independent timeout layers that both need to accommodate long-running pipes.

### Pipe timeout

The `timeout` property on each pipe defines the maximum server-side execution time in milliseconds. When the timeout elapses, the pipe cancels execution and returns a timeout exception to the caller. The default value `0` disables the pipe-level timeout.

```json
{
    "id": "ldap-heavy-pipe",
    "timeout": 120000,
    "config": {
        "valves": [...]
    }
}
```

### Event bus timeout

The caller-side transport has a separate, global send timeout. It controls how long the calling service waits for a reply over the internal event bus before giving up. The default is 30 seconds and is controlled by the JVM system property `fortified.server.eventBus.sendTimeoutMs`.

```
-Dfortified.server.eventBus.sendTimeoutMs=125000
```

### Coordinating the two timeouts

The event bus timeout must be greater than or equal to the pipe timeout. If the event bus timeout fires first, the caller receives a generic transport error instead of the more informative pipe timeout exception.

A small margin is recommended, for example setting the pipe timeout to 120 000 ms and the event bus timeout to 125 000 ms. This ensures that the pipe-level cancellation fires first and the caller receives a clear timeout exception with the pipe identity.

{% hint style="info" %}
When the pipe timeout is `0` (disabled), the event bus timeout is the only enforced limit. The default event bus timeout of 30 seconds applies unless overridden.
{% endhint %}
