Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
f3212e5
docs: make v5 the default docs version
VaguelySerious Jul 24, 2026
e784d32
docs: add "What's new in v5?" page, v4->v5 migration skill, sidebar fix
VaguelySerious Jul 24, 2026
a288295
Apply suggestions from code review
VaguelySerious Jul 24, 2026
4a6fabd
docs: rewrite v5 highlights around headline items, expand breaking ch…
VaguelySerious Jul 24, 2026
2c41b92
Merge origin/main into peter/docs-5-ga
VaguelySerious Jul 24, 2026
fd5898c
Polish writing
VaguelySerious Jul 24, 2026
82257ac
Polish
VaguelySerious Jul 24, 2026
4b22508
Merge origin/main into peter/docs-5-ga
VaguelySerious Jul 25, 2026
b36c1a1
docs: tidy v5 what's-new copy
VaguelySerious Jul 25, 2026
a0adc9e
docs: fix worlds version flip, drop stale lazyDiscovery claim, addres…
pranaygp Jul 27, 2026
ccbc70a
docs: address second round of what's-new toolbar feedback
pranaygp Jul 27, 2026
f6861c4
docs: cover remaining v5-only changes in what's-new, document analyti…
pranaygp Jul 27, 2026
44a53f0
docs: sweep v5 content for stale v4-era descriptions
pranaygp Jul 27, 2026
48b5b7a
docs: document the Analytics interface in Building a World
pranaygp Jul 27, 2026
eb4659d
docs: reframe comparison retry rows as idiomatic equivalence, surface…
pranaygp Jul 27, 2026
c27218d
Merge remote-tracking branch 'origin/main' into peter/docs-5-ga
pranaygp Jul 27, 2026
2f1c101
docs: bring snippet lint coverage up, tighten review follow-ups
pranaygp Jul 27, 2026
0ae61af
docs(v5): note the listByCorrelationId runId requirement
VaguelySerious Aug 2, 2026
9abe275
docs: make analytics contract portable, move Vercel pipeline behavior…
pranaygp Aug 3, 2026
77d568a
Merge origin/main into peter/docs-5-ga
VaguelySerious Aug 11, 2026
47d29a4
docs(worlds): scaffold the World upgrade guide route
VaguelySerious Aug 11, 2026
fefe947
docs: split the v5 what's-new page into user-facing and World-builder…
VaguelySerious Aug 11, 2026
334ca8f
Apply suggestion from @VaguelySerious
VaguelySerious Aug 11, 2026
391ac25
docs: event ID allocation is required for a v5 World
VaguelySerious Aug 11, 2026
faa7f6f
Apply suggestions from code review
VaguelySerious Aug 11, 2026
1ae1c4b
Merge remote-tracking branch 'origin/main' into peter/docs-5-ga
VaguelySerious Aug 11, 2026
fe8ab90
Merge remote-tracking branch 'origin/peter/docs-5-ga' into peter/docs…
VaguelySerious Aug 11, 2026
8fa19ed
docs: add the two v5 breaking changes that broke real apps
VaguelySerious Aug 11, 2026
76ed7ff
docs: slot allocation is required, and no World needs a precondition …
VaguelySerious Aug 13, 2026
d9ef7f3
docs: catch the migration skill up with the World contract changes
VaguelySerious Aug 13, 2026
4eafe07
Merge remote-tracking branch 'origin/main' into peter/docs-5-ga
VaguelySerious Aug 14, 2026
b89ebc8
docs: spec version 6 in the World upgrade guide, and a World migratio…
VaguelySerious Aug 14, 2026
ebf822d
Merge remote-tracking branch 'origin/main' into peter/docs-5-ga
VaguelySerious Aug 21, 2026
58d0d68
docs: split the version flip out of this PR
VaguelySerious Aug 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .changeset/docs-v5-whats-new-pages.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ Linting, formatting, and typechecking (`pnpm lint`, `pnpm format`, `pnpm typeche
When a PR adds or updates docs pages (anything under `docs/content/`), add a "Docs Preview" section to the PR description with direct links to each changed page on the `workflow-docs` preview deployment:

- Get the preview base URL from the `vercel[bot]` comment on the PR — use the Preview link from the `workflow-docs` project row (e.g. `https://workflow-docs-git-<branch-slug>.vercel.sh`). Don't construct the URL by hand; Vercel's branch-slug normalization is not a simple substitution.
- Map content paths to routes: `docs/content/docs/v4/<path>.mdx` is served at `/docs/<path>` (v4 is the default/latest version) and `docs/content/docs/v5/<path>.mdx` at `/v5/docs/<path>`.
- Map content paths to routes: `docs/content/docs/v5/<path>.mdx` is served at `/docs/<path>` (v5 is the default/latest version) and `docs/content/docs/v4/<path>.mdx` at `/v4/docs/<path>` (v4 is the maintenance version).
- When a change is scoped to a specific section of a page, link to its heading anchor (e.g. `/docs/foundations/hooks#checking-for-token-conflicts`) and verify the anchor matches a real heading in the MDX.
- A simple table with one row per page (and one column per docs version, when both v4 and v5 were updated) works well.
- The preview deployment sits behind deployment protection, so the links require Vercel team access — that's expected; include them anyway for reviewers.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,19 @@ import { DocsLayout } from '@/components/geistdocs/docs-layout';
import { getDocsTreeForVersion } from '@/lib/geistdocs/version-source';
import { LATEST_VERSION } from '@/lib/geistdocs/versions';

const Layout = async ({ children, params }: LayoutProps<'/[lang]/docs'>) => {
const { lang } = await params;
// This layout lives inside `[[...slug]]` rather than next to it so that

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question on the tradeoff: with the layout inside [[...slug]], it belongs to the dynamic segment, so client-side navigation between two docs pages re-renders it with new params — App Router only preserves layout state when the segment (including its param value) is unchanged. The practical symptom would be sidebar scroll position / drill-in state resetting on every page click, which the previous static docs/layout.tsx avoided. The PR verification covered prerendered output; did you also check client-side navigation in the browser? If geistdocs re-scrolls the active item into view this may be a fine trade for the hydration-flash-free activeSlug, but it affects every docs page, so worth confirming before GA.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Answered this empirically against the built server with a browser: the sidebar's scroll container IS remounted on every client-side navigation (a DOM marker set before navigating does not survive), but geistdocs re-scrolls the active item into view after each mount — verified in the long API-reference section (sidebar overflow ~2300px, scrollTop lands at the active link, active item visible after both direct load and client-side nav). So the practical UX is the standard docs behavior of following the current page, and the tradeoff for server-rendered activeSlug with no hydration flash holds. No change needed — resolving.

// `params.slug` is available: the sidebar needs the active page to decide
// whether to drill into a section. See `DocsLayout`.
const Layout = async ({
children,
params,
}: LayoutProps<'/[lang]/docs/[[...slug]]'>) => {
const { lang, slug } = await params;

return (
<div className="bg-background-200">
<DocsLayout
activeSlug={slug}
currentVersion={LATEST_VERSION.id}
lang={lang}
tree={getDocsTreeForVersion(lang, LATEST_VERSION)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,19 @@ import { PreReleaseBanner } from '@/components/geistdocs/pre-release-banner';
import { getDocsTreeForVersion } from '@/lib/geistdocs/version-source';
import { PRE_RELEASE_VERSION } from '@/lib/geistdocs/versions';

const Layout = async ({ children, params }: LayoutProps<'/[lang]/v5/docs'>) => {
const { lang } = await params;
// This layout lives inside `[[...slug]]` rather than next to it so that
// `params.slug` is available: the sidebar needs the active page to decide
// whether to drill into a section. See `DocsLayout`.
const Layout = async ({
children,
params,
}: LayoutProps<'/[lang]/v5/docs/[[...slug]]'>) => {
const { lang, slug } = await params;
return (
<div className="bg-background-200">
<PreReleaseBanner pathname={`/${lang}/v5/docs`} />
<DocsLayout
activeSlug={slug}
currentVersion={PRE_RELEASE_VERSION.id}
lang={lang}
tree={getDocsTreeForVersion(lang, PRE_RELEASE_VERSION)}
Expand Down
10 changes: 5 additions & 5 deletions docs/app/[lang]/v5/worlds/building-a-world/page.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import type { Metadata } from 'next';
import {
BuildingAWorldPage,
generateBuildingAWorldMetadata,
} from '@/components/worlds/building-a-world-page';
generateWorldsGuideMetadata,
WorldsGuidePage,
} from '@/components/worlds/worlds-guide-page';

export function generateMetadata(): Promise<Metadata> {
return generateBuildingAWorldMetadata('v5');
return generateWorldsGuideMetadata('building-a-world', 'v5');
}

export default function Page() {
return <BuildingAWorldPage version="v5" />;
return <WorldsGuidePage slug="building-a-world" version="v5" />;
}
13 changes: 13 additions & 0 deletions docs/app/[lang]/v5/worlds/upgrading-to-v5/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { Metadata } from 'next';
import {
generateWorldsGuideMetadata,
WorldsGuidePage,
} from '@/components/worlds/worlds-guide-page';

export function generateMetadata(): Promise<Metadata> {
return generateWorldsGuideMetadata('upgrading-to-v5', 'v5');
}

export default function Page() {
return <WorldsGuidePage slug="upgrading-to-v5" version="v5" />;
}
10 changes: 5 additions & 5 deletions docs/app/[lang]/worlds/building-a-world/page.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import type { Metadata } from 'next';
import {
BuildingAWorldPage,
generateBuildingAWorldMetadata,
} from '@/components/worlds/building-a-world-page';
generateWorldsGuideMetadata,
WorldsGuidePage,
} from '@/components/worlds/worlds-guide-page';

export function generateMetadata(): Promise<Metadata> {
return generateBuildingAWorldMetadata('v4');
return generateWorldsGuideMetadata('building-a-world', 'v4');
}

export default function Page() {
return <BuildingAWorldPage version="v4" />;
return <WorldsGuidePage slug="building-a-world" version="v4" />;
}
40 changes: 39 additions & 1 deletion docs/components/geistdocs/docs-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,19 +88,57 @@ const withFallbackFolderIndex = (nodes: DocsTreeNode[]): DocsTreeNode[] =>
};
});

// `/docs` permanently redirects here, so this is the page every bare link to
// the documentation lands on.
const DOCS_HOME_SECTION = 'getting-started';

/**
* geistdocs' sidebar has two panes: the top-level menu, and a section pane it
* drills into for the first root folder containing the active page. On the docs
* home that drill-in is unhelpful — arriving from a `/docs` link would replace
* the top-level menu with the framework list, hiding the rest of the docs.
*
* `findActiveRootSection` only matches folders that have children, so emptying
* the section's children on its own landing page keeps the root menu visible
* with the row highlighted as the current page. Nothing is lost: the page body
* is a card grid of exactly those children, and every other page in the section
* still drills in normally.
*/
const collapseDocsHomeSection = (
tree: DocsTree,
activeSlug?: string[]
): DocsTree => {
if (activeSlug?.join('/') !== DOCS_HOME_SECTION) {
return tree;
}

return {
...tree,
children: tree.children.map((node) =>
node.type === 'folder' &&
node.index?.url.endsWith(`/docs/${DOCS_HOME_SECTION}`)
? { ...node, children: [] }
: node
),
};
};

const addSidebarBadgesToTree = (tree: DocsTree): DocsTree => ({
...tree,
children: addSidebarBadges(withFallbackFolderIndex(tree.children)),
});

interface DocsLayoutProps {
/** Slug of the active page, used to tune sidebar drill-in behavior. */
activeSlug?: string[];
children: ReactNode;
currentVersion?: string;
lang: string;
tree: ComponentProps<typeof PackageDocsLayout>['tree'];
}

export const DocsLayout = ({
activeSlug,
tree,
currentVersion = config.versions?.current,
lang,
Expand All @@ -123,7 +161,7 @@ export const DocsLayout = ({
/>
) : null
}
tree={addSidebarBadgesToTree(tree)}
tree={collapseDocsHomeSection(addSidebarBadgesToTree(tree), activeSlug)}
>
{children}
</PackageDocsLayout>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import type { DocsVersionId } from '@/lib/geistdocs/versions';
import { WorldDetailToc } from './WorldDetailToc';
import { WorldVersionSelect } from './WorldVersionSelect';

const PAGE_SLUGS = ['building-a-world'];

const VERSION_SOURCES = {
v4: worldsSource,
v5: v5WorldsSource,
Expand All @@ -22,13 +20,19 @@ const VERSION_PREFIXES = {
v5: '/v5',
} as const;

export async function generateBuildingAWorldMetadata(
/**
* Standalone guide pages in the worlds tree — the ones that are not a world
* detail page. They render outside the docs sidebar, so each is a bespoke
* route passing its own slug.
*/
export async function generateWorldsGuideMetadata(
slug: string,
version: DocsVersionId
): Promise<Metadata> {
const page = VERSION_SOURCES[version].getPage(PAGE_SLUGS);
const page = VERSION_SOURCES[version].getPage([slug]);

if (!page) {
return { title: 'Building a World | Workflow SDK' };
return { title: 'Worlds | Workflow SDK' };
}

const versionPrefix = VERSION_PREFIXES[version];
Expand All @@ -41,9 +45,9 @@ export async function generateBuildingAWorldMetadata(
images: ['/og/worlds'],
},
alternates: {
canonical: '/worlds/building-a-world',
canonical: `/worlds/${slug}`,
types: {
'text/markdown': `${versionPrefix}/worlds/building-a-world.md`,
'text/markdown': `${versionPrefix}/worlds/${slug}.md`,
},
},
...(isPreRelease
Expand All @@ -57,14 +61,16 @@ export async function generateBuildingAWorldMetadata(
};
}

export async function BuildingAWorldPage({
export async function WorldsGuidePage({
slug,
version,
}: {
slug: string;
version: DocsVersionId;
}) {
const source = VERSION_SOURCES[version];
const versionPrefix = VERSION_PREFIXES[version];
const page = source.getPage(PAGE_SLUGS);
const page = source.getPage([slug]);

if (!page) {
notFound();
Expand Down
2 changes: 1 addition & 1 deletion docs/content/docs/v4/deploying.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ vercel deploy
</Callout>

<Callout type="info">
Starting with `workflow` version 5.0.0-beta.33, the Vercel World supports
Starting with `workflow` version 5.0.0, the Vercel World supports
**multi-region**: runs are pinned to the region that creates them, keeping
workflow data, queuing, and streaming close to your users. See
[Multi-region](/v5/worlds/vercel#multi-region).
Expand Down
2 changes: 1 addition & 1 deletion docs/content/docs/v4/getting-started/next.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ Build error occurred
Error: Cannot find module 'next/dist/lib/server-external-packages.json'
```

Upgrade to `workflow@4.0.1-beta.26` or later:
Upgrade to `workflow@4.0.1` or later:

```package-install
workflow@latest
Expand Down
1 change: 0 additions & 1 deletion docs/content/docs/v5/ai/defining-tools.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ Just like in regular AI SDK tool definitions, tool in WorkflowAgent are called w
When you tool needs access to the full message history, you can access it via the `messages` property of the tool call context:

```typescript title="tools.ts" lineNumbers
import { Experimental_Agent as Agent } from "ai";
import type { ModelMessage } from "ai";

async function getWeather(
Expand Down
1 change: 1 addition & 0 deletions docs/content/docs/v5/ai/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"sleep-and-delays",
"human-in-the-loop",
"defining-tools",
"message-queueing",
"chat-session-modeling"
],
"defaultOpen": true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ Learn more about [`WorkflowReadableStreamOptions`](/docs/api-reference/workflow-
* All arguments must be [serializable](/docs/foundations/serialization).
* When `deploymentId` is provided, the argument types and return type become `unknown` since there is no guarantee the workflow function's types will be consistent across different deployments.
* `attributes` seeds plaintext run metadata as part of creation and requires a World implementing spec version 4 or later. Keys that start with `$` are reserved for framework and library code; framework-level callers can pass `allowReservedAttributes: true` to seed reserved keys, with the same semantics as the [`setAttributes`](/docs/api-reference/workflow/set-attributes) option of the same name.
* `region` pins the new run to a specific region on Worlds with a regional dimension. On the [Vercel World](/worlds/vercel#explicit-region-selection) the run's storage, queue dispatch, and streams are then served from that region; when omitted, the run is pinned to the region it was created in. Worlds without regions ignore the option.

<Callout type="info">
If `start()` throws `'start' received an invalid workflow function. Ensure the Workflow SDK is configured correctly and the function includes a 'use workflow' directive.`, the passed function was not transformed as a workflow. The two most common causes are a missing `"use workflow"` directive or missing framework integration. See [start-invalid-workflow-function](/docs/errors/start-invalid-workflow-function).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ related:

No world in this repository throws it. A stale replay does not need to be refused: its log is a prefix rather than a prefix with a hole in it, replay is deterministic on a prefix, and the write it makes next comes back carrying the events it was pushed past (see [Stale reads](/docs/configuration/runtime-tuning#stale-reads-and-why-nothing-has-to-be-rejected)). The error and the runtime's handling of it remain for a world that would rather refuse than report — one that allocates positions somewhere other than the commit, and so cannot report a gap reliably. Event creations that carry no position are never rejected with it.

A world rejects only on evidence and accepts the creation whenever it cannot decide, so this error always means the snapshot really was stale — but not receiving it does not prove the snapshot was current.
A World rejects only on evidence and accepts the creation whenever it cannot decide, so this error always means the snapshot really was stale — but not receiving it does not prove the snapshot was current.

<Callout>
The Workflow runtime handles this error automatically: it restarts the replay in the same invocation from a corrected event log, and re-invokes the run for a fresh replay only once its in-process restart budget is spent. It never retries the rejected creation as-is, because a replay working from a corrected log derives different events. You will only encounter it when interacting with world storage APIs directly.
Expand Down
1 change: 1 addition & 0 deletions docs/content/docs/v5/api-reference/workflow-globals.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ These standard Web APIs are available in workflow functions:
- [`console`](https://developer.mozilla.org/en-US/docs/Web/API/console)
- [`structuredClone`](https://developer.mozilla.org/en-US/docs/Web/API/Window/structuredClone)
- [`atob`](https://developer.mozilla.org/en-US/docs/Web/API/Window/atob) / [`btoa`](https://developer.mozilla.org/en-US/docs/Web/API/Window/btoa)
- [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) / [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) — a durable, serializable implementation whose abort state survives replay and can be passed into steps to cancel in-flight work. See [Cancellation](/docs/foundations/cancellation).

## Environment Variables

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
title: createWorld
description: Create a new World instance from environment configuration.
type: reference
summary: Use createWorld to instantiate a World from WORKFLOW_TARGET_WORLD environment configuration, bypassing the cached instance.
summary: Use createWorld to construct a fresh instance of the build-injected World, bypassing the cached instance.
prerequisites:
- /docs/api-reference/workflow-runtime/get-world
related:
- /docs/api-reference/workflow-runtime/set-world
---

Creates a new [World](/docs/api-reference/workflow-runtime/world) instance based on environment configuration. The `WORKFLOW_TARGET_WORLD` environment variable determines which World implementation is instantiated (for example the local development World or the Vercel production World).
Creates a new [World](/docs/api-reference/workflow-runtime/world) instance by invoking the World factory that was statically injected into the bundle at build time. Which implementation that is (for example the local development World or the Vercel production World) is decided when the app is built, via the `WORKFLOW_TARGET_WORLD` environment variable — changing the variable at runtime has no effect.

Unlike [`getWorld()`](/docs/api-reference/workflow-runtime/get-world), which caches a singleton instance, `createWorld()` constructs a fresh instance on every call. Application code should almost always use `getWorld()` — `createWorld()` is for infrastructure code that manages World lifecycles itself.

Expand All @@ -23,7 +23,7 @@ const world = await createWorld(); // [!code highlight]

### Parameters

This function does not accept any parameters. Configuration is read from environment variables.
This function does not accept any parameters. Configuration comes from the World that was injected at build time (World implementations typically read their own settings from environment variables when constructed).

### Returns

Expand Down
22 changes: 12 additions & 10 deletions docs/content/docs/v5/api-reference/workflow-runtime/set-world.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
title: setWorld
description: Override or reset the cached World instance used by the workflow runtime.
type: reference
summary: Use setWorld to inject a custom World instance or reset the cache after environment configuration changes.
summary: Use setWorld to inject a custom World instance or reset the cache to the build-injected World.
prerequisites:
- /docs/api-reference/workflow-runtime/get-world
related:
- /docs/api-reference/workflow-runtime/create-world
---

Overrides the cached [World](/docs/api-reference/workflow-runtime/world) instance that [`getWorld()`](/docs/api-reference/workflow-runtime/get-world) returns. Use it to inject a World constructed with explicit configuration (rather than environment variables), or pass `undefined` to clear the cache so the next `getWorld()` call reinitializes from the current environment.
Overrides the cached [World](/docs/api-reference/workflow-runtime/world) instance that [`getWorld()`](/docs/api-reference/workflow-runtime/get-world) returns. Use it to inject a World constructed with explicit configuration, or pass `undefined` to clear the cache so the next `getWorld()` call reconstructs the World that was statically injected into the bundle at build time.

```typescript lineNumbers
import { setWorld, getWorld } from "workflow/runtime";
Expand All @@ -26,24 +26,26 @@ const world = await getWorld(); // resolves customWorld

| Parameter | Type | Description |
|-----------|------|-------------|
| `world` | `World \| undefined` | The World instance to use, or `undefined` to reset the cache and reinitialize from environment variables on next access |
| `world` | `World \| undefined` | The World instance to use, or `undefined` to reset the cache so the next access reconstructs the build-injected World |

### Returns

This function does not return a value.

## Example: Reset After Environment Changes
## Example: Inject a Specific World

```typescript lineNumbers
import { setWorld, getWorld } from "workflow/runtime";
The target World is selected at build time (via `WORKFLOW_TARGET_WORLD` when the app was built) and statically injected into the bundle — changing the environment variable at runtime has no effect. To use a different World at runtime, construct it explicitly with the World package's `createWorld()` factory and inject it:

process.env.WORKFLOW_TARGET_WORLD = "@workflow/world-local";
setWorld(undefined); // clear the cached instance // [!code highlight]
```typescript lineNumbers
import { setWorld } from "workflow/runtime";
import { createWorld } from "@workflow/world-local";

const world = await getWorld(); // reinitialized with new configuration
setWorld(createWorld({ dataDir: "/tmp/workflow-test" })); // [!code highlight]
```

Calling `setWorld(undefined)` afterwards restores the build-injected World on the next `getWorld()` call.

## Related Functions

- [`getWorld()`](/docs/api-reference/workflow-runtime/get-world) - Resolve the cached World instance.
- [`createWorld()`](/docs/api-reference/workflow-runtime/create-world) - Construct a fresh World from environment configuration.
- [`createWorld()`](/docs/api-reference/workflow-runtime/create-world) - Construct a fresh instance of the build-injected World.
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ const world = await getWorld(); // [!code highlight]
The World SDK is the low-level foundation that higher-level functions like [`getRun()`](/docs/api-reference/workflow-api/get-run) and [`start()`](/docs/api-reference/workflow-api/start) are built on. Use it when you need capabilities beyond what those functions provide.
</Callout>

Beyond these namespaces, the `World` interface carries a handful of top-level members aimed at World authors — `specVersion`, `capabilities`, lifecycle hooks (`start()`/`close()`), `getEncryptionKeyForRun()`, and the optional `createRunId()` / `describeRun()` hooks behind regional run placement and world-specific `inspect` output. Those are documented in [Building a World](/worlds/building-a-world).

## Data Hydration

Step input/output data is serialized using the [devalue](https://github.com/Rich-Harris/devalue) format. To display this data in your UI, use the hydration utilities from `workflow/observability`:
Expand Down
Loading
Loading