# @modular-react/journeys Typed, serializable workflows that compose several modules. A journey declares how one module's exit feeds the next module's entry; the modules themselves stay journey-unaware - they just declare what input they accept and what outcomes they can emit. Use this package when a domain flow spans multiple modules with **shared state** (e.g. "confirm the customer's profile → branch into plan selection → collect a payment or activate a free trial"), and you want: - typed end-to-end module boundaries, - serializable state so a mid-flow reload or hand-off survives, - a single place that owns transitions, instead of cross-cutting glue inside module stores. Routes, slots, navigation, workspaces - none of that changes. Journeys sit **on top** of the existing framework. Apps that don't register a journey incur nothing beyond the package being statically linked. ## Prerequisite reading - [Shell Patterns (Fundamentals)](../../docs/shell-patterns.md) - [Workspace Patterns](../../docs/workspace-patterns.md) ## Contents - [Installation](#installation) - [Mental model](#mental-model) - [Quickstart shortcut: scaffold the journey package](#quickstart-shortcut-scaffold-the-journey-package) - `create journey` if you bootstrapped with the modular-react CLI - [Quickstart](#quickstart) - the 5-step path from zero to a running journey - [Core concepts](#core-concepts) - entries, exits, `allowBack`, lifecycle, statuses, keys - [Authoring patterns](#authoring-patterns) - module entries, exits, loading flows, **event-driven wait (websocket / SSE + polling + timeout)**, `goBack` opt-in, **lazy entry-points (code-splitting)** - [Journey definition patterns](#journey-definition-patterns) - branching, `selectModule` dispatch, terminals, state rewrites, bounded history, module compatibility, **`defineTransition` (auto-preload + narrowed handler return)**, **wildcard transitions + shared exit contracts** - [Composing journeys (invoke / resume)](#composing-journeys-invoke--resume) - call out to a child journey mid-flow and resume on its outcome - [Cycle and recursion safety](#cycle-and-recursion-safety) - cycle / depth / undeclared-child / bounce-limit guards and how to tune them - [Runtime surface](#runtime-surface) - the `JourneyRuntime` you get back from `manifest.journeys` - [Journey handles](#journey-handles) - typed tokens for `runtime.start(handle, input)` - [`JourneyProvider` + context](#journeyprovider--context) - [Persistence](#persistence) - adapters, key design, save queue, hydrate vs start, versioning - [Rendering - `JourneyOutlet`](#rendering--journeyoutlet) - props, error policies, host rules - [Hosting a journey - `JourneyHost`](#hosting-a-journey---journeyhost) - start on mount, end + forget on unmount, step index - [Deep-linking steps - `useJourneySync`](#deep-linking-steps---usejourneysync) - journey ↔ URL in both directions, ports, what a URL can and cannot select - [Hosting plain modules - `ModuleTab`](#hosting-plain-modules--moduletab) - [Observation hooks](#observation-hooks) - [Testing](#testing) - module-level, pure simulator, integration, persistence adapters - [Integration patterns](#integration-patterns) - tabs, modals, routes, wizards, command palette - [Embedding a journey in a composition zone](#embedding-a-journey-in-a-composition-zone) - wiring `createJourneyMountAdapter` so a `@modular-react/compositions` zone can mount a journey - [Debugging](#debugging) - dev-mode warnings and introspection - [Errors, races, and edge cases](#errors-races-and-edge-cases) - [Limitations](#limitations) - [TypeScript inference notes](#typescript-inference-notes) - [API reference](#api-reference) - [Example projects](#example-projects) ## Installation The journey runtime is already a transitive dependency of `@react-router-modules/runtime` and `@tanstack-react-modules/runtime`. Install it directly only when the shell needs to type against journey types (usually it does): ```bash pnpm add @modular-react/journeys ``` Peer deps: `@modular-react/core`, `@modular-react/react`, `react`, `react-dom`. If you scaffolded your project with the modular-react CLI, you can scaffold a journey package the same way - see [§ Quickstart shortcut: scaffold the journey package](#quickstart-shortcut-scaffold-the-journey-package) below. ## Using this with Vue There's a full Vue 3 binding: **`@modular-vue/journeys`** (peer deps `@modular-frontend/core`, `@modular-vue/vue`, `vue`). The journey _engine_ — `defineJourney`, transitions, branching, persistence, rewind, the runtime, handles, `selectModule*`, and every type — is framework-neutral (it lives in `@modular-frontend/journeys-engine`) and is re-exported identically by both bindings, so **journey definitions and module entry/exit contracts are written exactly the same way** whichever framework you ship. What changes is the UI layer: - Import the outlet, provider, plugin, and composables from `@modular-vue/journeys` instead of `@modular-react/journeys`. ``, ``, ``, `journeysPlugin()`, `useJourneyState`, `useWaitForExit` all have the same names and roles. - Journey steps are module-entry SFCs: `defineProps>()` and call the typed `exit(name, payload)` — the analog of the React entry component's props. - The subscription composables return **Vue refs** rather than plain values (e.g. `useJourneyState` → `ComputedRef`), matching the rest of the Vue binding; read `.value` in `