Local World

The Local World (@workflow/world-local) is a filesystem-based workflow backend designed for local development and testing. It stores workflow data as JSON files on disk and provides in-memory queuing.

The local world is perfect for local development because it:

  • Requires no external services or configuration
  • Stores data as readable JSON files for easy debugging
  • Provides instant feedback during development
  • Works seamlessly with Next.js development server

How It Works

Storage

The local world stores all workflow data as JSON files in a configurable directory:

.workflow-data/
├── runs/
│   └── <run-id>.json
├── steps/
│   └── <run-id>/
│       └── <step-id>.json
├── hooks/
│   └── <hook-id>.json
└── streams/
    └── <run-id>/
        └── <stream-id>.json

Each file contains the full state of a run, step, hook, or stream, making it easy to inspect workflow data directly.

Queuing

The local world uses an in-memory queue with HTTP transport:

  1. When a step is enqueued, it's added to an in-memory queue
  2. The queue processes steps by sending HTTP requests to your development server
  3. Steps are executed at the .well-known/workflow/v1/step endpoint

The queue automatically detects your development server's port and adjusts the queue URL accordingly.

Authentication

The local world provides a simple authentication implementation since no authentication is required or enforced in local development.

getAuthHeaders(): Promise<Record<string, string>> {
  return Promise.resolve({});
}

Configuration

Data Directory

By default, workflow data is stored in .workflow-data/ in your project root. This can be customized through environment variables or programmatically.

Environment variable:

export WORKFLOW_EMBEDDED_DATA_DIR=./custom-workflow-data

Programmatically:

import { createEmbeddedWorld } from '@workflow/world-local';

const world = createEmbeddedWorld({ dataDir: './custom-workflow-data' });

Port

By default, the embedded world automatically detects which port your application is listening on using process introspection. This works seamlessly with frameworks like SvelteKit, Vite, and others that use non-standard ports.

Auto-detection example (recommended):

import { createEmbeddedWorld } from '@workflow/world-local';

// Port is automatically detected - no configuration needed!
const world = createEmbeddedWorld();

If auto-detection fails, the world will fall back to the PORT environment variable, then to port 3000.

Manual port override (when needed):

You can override the auto-detected port by specifying it explicitly:

import { createEmbeddedWorld } from '@workflow/world-local';

const world = createEmbeddedWorld({ port: 3000 });

Base URL

For advanced use cases like HTTPS or custom hostnames, you can override the entire base URL. When set, this takes precedence over all port detection and configuration.

Use cases:

  • HTTPS dev servers (e.g., next dev --experimental-https)
  • Custom hostnames (e.g., local.example.com)
  • Non-localhost development

Environment variable:

export WORKFLOW_EMBEDDED_BASE_URL=https://local.example.com:3000

Programmatically:

import { createEmbeddedWorld } from '@workflow/world-local';

// HTTPS
const world = createEmbeddedWorld({
  baseUrl: 'https://localhost:3000'
});

// Custom hostname
const world = createEmbeddedWorld({
  baseUrl: 'https://local.example.com:3000'
});

Usage

The local world is used automatically during local development:

# Start your Next.js dev server
npm run dev

# Workflows automatically use local world

Manual

You can explicitly set the local world through environment variables:

export WORKFLOW_TARGET_WORLD=local

npm run dev

Development Workflow

A typical development workflow with local world:

  1. Start your dev server:

    npm run dev
  2. Trigger a workflow:

    curl -X POST --json '{"email":"test@example.com"}' http://localhost:3000/api/signup
  3. Inspect the results:

    • Use the CLI or Web UI
    • Check JSON files in .workflow-data/
    • View development server logs

Inspecting Data

Using Observability Tools

The local world integrates with the Workflow DevKit's observability tools:

# View runs with CLI
npx workflow inspect runs

# View runs with Web UI
npx workflow inspect runs --web

Learn more in the Observability section.

Limitations

The local world is designed for development, not production:

  • Not scalable - Uses in-memory queuing
  • Not persistent - Data is stored in local files
  • Single instance - Cannot handle distributed deployments
  • No authentication - Suitable only for local development

For production deployments, use the Vercel World.

API Reference

createEmbeddedWorld

Creates a local world instance:

function createEmbeddedWorld(
  args?: Partial<{
    dataDir: string;
    port: number;
    baseUrl: string;
  }>
): World

Parameters:

  • args - Optional configuration object:
    • dataDir - Directory for storing workflow data (default: .workflow-data/ or WORKFLOW_EMBEDDED_DATA_DIR env var)
    • port - Port override for queue transport (default: auto-detected → PORT env var → 3000)
    • baseUrl - Full base URL override for queue transport (default: http://localhost:{port} or WORKFLOW_EMBEDDED_BASE_URL env var)

Returns:

  • World - A world instance implementing the World interface

Examples:

import { createEmbeddedWorld } from '@workflow/world-local';

// Use all defaults (recommended - auto-detects port)
const world = createEmbeddedWorld();

// Custom data directory
const world = createEmbeddedWorld({ dataDir: './my-data' });

// Override port
const world = createEmbeddedWorld({ port: 3000 });

// HTTPS with custom hostname
const world = createEmbeddedWorld({
  baseUrl: 'https://local.example.com:3000'
});

// Multiple options
const world = createEmbeddedWorld({
  dataDir: './my-data',
  baseUrl: 'https://localhost:3000'
});

Learn More