Skip to content

Fragments

Fragments are reusable, composable partial flows — the Flowneer equivalent of Zod partials. Define a step chain once, then splice it into any number of flows with .add().

Creating a Fragment

Use the fragment<S, P>() factory function. It returns a Fragment instance that supports the full fluent API: .then(), .loop(), .batch(), .branch(), .parallel(), .anchor().

typescript
import { fragment } from "flowneer";

const enrich = fragment<MyState>().then(fetchUser).then(enrichProfile);

const summarise = fragment<MyState>().loop(
  (s) => !s.done,
  (b) => b.then(summarize),
);

Fragments are typed — Fragment<S, P> carries the same shared-state and params types as FlowBuilder<S, P>, giving you full type safety when composing flows.


Embedding with .add()

Call .add(fragment) on any FlowBuilder to splice the fragment's steps inline at that position:

typescript
import { FlowBuilder, fragment } from "flowneer";

const flow = new FlowBuilder<MyState>()
  .then(init)
  .add(enrich) // enrich's steps are inlined here
  .add(summarise) // summarise's steps follow
  .then(finalize);

await flow.run(shared);

This is equivalent to manually chaining every step from the fragment — .add() just copies them in order.


Reuse Across Flows

The same fragment instance can be .add()-ed into multiple flows without conflict. Steps are copied by reference (same semantics as loop / batch inner builders).

typescript
const validate = fragment<State>().then(checkInput).then(sanitize);

const flowA = new FlowBuilder<State>().add(validate).then(handleA);
const flowB = new FlowBuilder<State>().add(validate).then(handleB);

Fragments Cannot Run Directly

Calling .run() or .stream() on a Fragment throws an error:

typescript
const frag = fragment().then(myStep);

await frag.run({}); // ❌ Error: Fragment cannot be run directly — use .add()

This is by design — fragments are building blocks, not standalone flows. Always embed them via .add().


All Step Types Supported

Fragments can contain any step type:

typescript
const complex = fragment<State>()
  .then(stepA)
  .branch((s) => s.mode, {
    fast: stepFast,
    slow: stepSlow,
  })
  .loop(
    (s) => !s.done,
    (b) => b.then(iterate),
  )
  .batch(
    (s) => s.items,
    (b) => b.then(processItem),
  )
  .parallel([workerA, workerB])
  .anchor("checkpoint");

When .add(complex) is called, all of these steps are inlined into the parent flow and execute as if they were defined directly on it.


Composing Fragments

Fragments can .add() other fragments, enabling layered composition:

typescript
const auth = fragment<State>().then(authenticate).then(authorize);
const enrich = fragment<State>().then(fetchProfile).then(loadPrefs);

const setup = fragment<State>().add(auth).add(enrich);

const flow = new FlowBuilder<State>().add(setup).then(handleRequest);

API Reference

fragment<S, P>()

Factory function that creates a new Fragment<S, P>.

typescript
import { fragment } from "flowneer";
const frag = fragment<MyState>();

Fragment<S, P>

Class extending FlowBuilder<S, P>. Inherits all builder methods. Overrides .run() and .stream() to throw.

.add(frag)

Method on FlowBuilder that splices all steps from frag into the current flow.

ParameterTypeDescription
fragFlowBuilder<S, P>A fragment (or FlowBuilder) to inline

Returns this for chaining.