Genel bakış

Flow Motivation

Why Flow was created and what problems it is designed to solve.

Flow was created for the kind of async application logic that starts as one readable function, then grows into retries, timeouts, parallel calls, fallback branches, and cancellation. Promise chains can express that work, but the important contract often ends up spread across exceptions, comments, and informal conventions.

The goal is to make those contracts visible. A Flow Behavior declares its input, output, expected failure type, and context. Composition helpers preserve those types while keeping runtime behavior predictable.

Why Flow exists

Flow exists because application workflows usually have more than one kind of failure. Some failures are expected business outcomes. Some are runtime faults. Some work should stop because a parent operation timed out or a sibling branch already made the result unusable.

When those states all travel through throw, ad hoc booleans, or loosely shaped return objects, the workflow becomes harder to compose and harder to test. Flow gives those states a small, typed structure.

What it optimizes for

Flow optimizes for application code that needs explicit outcomes. Expected failures are returned as typed Result values. Unexpected thrown errors are kept separate. Cancellation moves through an AbortSignal instead of being handled as an afterthought.

That shape makes workflows easier to test because each step can be run as a small unit, then composed into larger Behavior values with helpers such as task, pipe, all, and timeout.

Why not plain promises?

Plain promises are the right primitive for async work, and Flow is built on top of them. The missing piece is structure around the parts promises intentionally leave open: which failures are expected, which failures are runtime faults, how child work is cancelled, and how output types move through larger workflows.

Flow adds that structure without replacing the platform. Existing async functions become Behavior values through task, then use ordinary TypeScript types to describe the contract.

Why not a framework?

Flow is deliberately a small library instead of an application framework. It does not own routing, rendering, data fetching, storage, or deployment. It is meant to live inside those systems where workflow logic needs a clearer boundary.

The registry format also keeps ownership local. Installing a helper copies source into the project, so teams can inspect it, modify it, and remove pieces they do not need.

Where it fits

Flow fits best in service functions, server actions, background jobs, CLI tasks, and other places where async business logic has real failure states. It is less useful for simple one-off effects where a direct await is already clear.

Start with Getting Started for the mental model, then use the FAQ for installation choices and helper comparisons.

Current direction

The current design direction is intentionally small: preserve TypeScript types, keep runtime behavior explicit, and make cancellation part of the workflow contract. Naming, helper boundaries, generated registry files, and API details may still change as Flow is tested against more real workflows.