> Part of the walkerOS documentation. Project overview and full index: <https://www.walkeros.io/llms.txt>

# Flow

Flow configuration is walkerOS's **"configuration as code"** approach. A single JSON file defines your entire event collection pipeline, making it portable, version-controlled, and deployable across environments.

Reference page

This page is the complete Flow configuration reference. If you are new to walkerOS, start with the [Quickstart](https://www.walkeros.io/docs/getting-started/quickstart.md) and the [GA4 ecommerce tutorial](https://www.walkeros.io/docs/getting-started/ga4-ecommerce.md), then come back here to look up specific options.

## Configuration structure[​](#configuration-structure "Direct link to Configuration structure")

A flow configuration uses the `Flow.Json` format with two required fields:

1. **`version`** - Schema version (`4`)
2. **`flows`** - Named flow configurations (each a `Flow`)

### Basic example[​](#basic-example "Direct link to Basic example")

```
{
  "version": 4,
  "flows": {
    "default": {
      "config": {
        "platform": "web",
        "bundle": {
          "packages": {
            "@walkeros/web-source-browser": { "imports": ["sourceBrowser"] },
            "@walkeros/web-destination-api": { "imports": ["destinationAPI"] }
          }
        }
      },
      "sources": {
        "browser": {
          "package": "@walkeros/web-source-browser",
          "config": {
            "settings": {
              "pageview": true,
              "session": true
            }
          }
        }
      },
      "destinations": {
        "api": {
          "package": "@walkeros/web-destination-api",
          "config": {
            "settings": {
              "url": "https://analytics.example.com/events",
              "method": "POST",
              "headers": {
                "Content-Type": "application/json",
                "Authorization": "Bearer your-api-key"
              }
            }
          }
        }
      },
      "collector": { "run": true }
    }
  }
}
```

This captures browser DOM events and sends them to your analytics API endpoint via HTTP POST requests.

## Config syntax: `package:` vs `code:`[​](#config-syntax-package-vs-code "Direct link to config-syntax-package-vs-code")

When configuring sources and destinations, you'll see two different syntaxes depending on your operating mode.

### Bundled mode (JSON with CLI)[​](#bundled-mode-json-with-cli "Direct link to Bundled mode (JSON with CLI)")

Use `package:` with a string reference. The CLI downloads and bundles the npm package:

```
"sources": {
    "browser": {
      "package": "@walkeros/web-source-browser",
      "config": { "settings": { "pageview": true } }
    }
}
```

### Integrated mode (TypeScript with startFlow)[​](#integrated-mode-typescript-with-startflow "Direct link to Integrated mode (TypeScript with startFlow)")

Use `code:` with a direct import reference:

```
import { startFlow } from '@walkeros/collector';
import { sourceBrowser } from '@walkeros/web-source-browser';

const flow = await startFlow({
  sources: {
    browser: {
      code: sourceBrowser,
      config: { settings: { pageview: true } }
    }
  }
});
```

### Quick reference[​](#quick-reference "Direct link to Quick reference")

| Property   | Mode       | Value                      | When to Use                       |
| ---------- | ---------- | -------------------------- | --------------------------------- |
| `package:` | Bundled    | `"@walkeros/..."` (string) | CLI resolves and bundles from npm |
| `code:`    | Integrated | `sourceBrowser` (import)   | Direct code reference in your app |

Both achieve the same result. The difference is whether the CLI bundles the code for you (Bundled) or you import it directly (Integrated).

See [Operating Modes](https://www.walkeros.io/docs/getting-started/modes.md) for more details on choosing your approach.

## Flow configuration (Flow)[​](#flow-configuration-flow "Direct link to Flow configuration (Flow)")

Each flow in `flows` is a `Flow` that defines runtime behavior. Per-flow build/runtime metadata sits inside `config` (`Flow.Config`).

### Platform[​](#platform "Direct link to Platform")

Platform is set explicitly via `config.platform`:

```
{
    "version": 4,
    "flows": {
      "default": {
        "config": { "platform": "server" }
      }
    }
}
```

```
{
    "version": 4,
    "flows": {
      "default": {
        "config": { "platform": "web" }
      }
    }
}
```

**Platform options:**

* `"platform": "server"` - Node.js server environment (HTTP endpoints, cloud functions)
* `"platform": "web"` - Browser environment (client-side tracking)

The CLI automatically applies platform-specific build defaults:

* **Web**: IIFE format, ES2020 target
* **Server**: ESM format, Node20 target

The bundle is written to stdout by default. Use `-o` to write to a file (e.g., `-o ./dist/walker.js` for web, `-o ./dist/bundle.mjs` for server).

### Bundle[​](#bundle "Direct link to Bundle")

Build-time configuration lives under `flow.<name>.config.bundle`. The `packages` field specifies npm packages to download and bundle, and `overrides` pins transitive dependency versions (npm `overrides` semantics):

```
{
  "config": {
    "platform": "web",
    "bundle": {
      "packages": {
        "@walkeros/web-source-browser": {
          "version": "0.4.0",
          "imports": ["sourceBrowser"]
        },
        "@walkeros/web-destination-api": {
          "imports": ["destinationAPI"]
        }
      },
      "overrides": {
        "@amplitude/analytics-types": "2.11.1"
      }
    }
  }
}
```

**`packages` properties:**

* **`version`** - npm version (semver or "latest", defaults to "latest")
* **`imports`** - Array of named exports to import
* **`path`** - Local filesystem path (takes precedence over `version`)

**`overrides`** is a `Record<string, string>`: for each named package, the version to use for any transitive reference. Direct package specs always win over overrides; overrides only substitute transitive dependencies during resolution.

For development or custom packages, use `path` to reference a local directory:

```
{
  "config": {
    "platform": "web",
    "bundle": {
      "packages": {
        "@my/custom-destination": {
          "path": "./my-destination",
          "imports": ["myDestination"]
        }
      }
    }
  }
}
```

See [Local Packages](https://www.walkeros.io/docs/apps/cli.md#local-packages) in the CLI documentation for more details.

### Step-level package versions[​](#step-level-package-versions "Direct link to Step-level package versions")

When configuring individual steps (sources, transformers, or destinations), the `package` field accepts an optional inline version suffix:

```
{
  "sources": {
    "browser": {
      "package": "@walkeros/web-source-browser@2.1.0",
      "config": { "settings": { "pageview": true } }
    }
  }
}
```

If the same package is pinned in `config.bundle.packages` to a different version, the bundle-level pin takes precedence and the inline version is ignored (with a build warning).

### Sources[​](#sources "Direct link to Sources")

Sources capture events from various inputs. Each source needs:

* **`package`** - The npm package (required for package-based sources, optional when using `code:`)
* **`config`** - Source-specific settings

```
{
  "sources": {
    "http": {
      "package": "@walkeros/server-source-express",
      "config": {
        "settings": {
          "path": "/collect",
          "port": 8080,
          "cors": true
        }
      }
    }
  }
}
```

See [Sources documentation](https://www.walkeros.io/docs/sources.md) for all available options.

### Destinations[​](#destinations "Direct link to Destinations")

Destinations receive processed events and send them to analytics tools, databases, or APIs:

```
{
  "destinations": {
    "bigquery": {
      "package": "@walkeros/server-destination-gcp",
      "config": {
        "settings": {
          "projectId": "my-project",
          "datasetId": "analytics",
          "tableId": "events"
        },
        "mapping": {
          "page": {
            "view": {
              "name": "page_view"
            }
          }
        }
      }
    },
    "console": {
      "package": "@walkeros/destination-demo",
      "config": {
        "settings": {
          "name": "Debug Logger"
        }
      }
    }
  }
}
```

**Configuration options:**

* **`settings`** - Destination-specific configuration (API keys, endpoints, etc.)
* **`mapping`** - Event transformation rules (see [Mapping documentation](https://www.walkeros.io/docs/mapping.md))
* **`consent`** - Required consent states
* **`policy`** - Processing rules

**Conditional activation:**

Sources and destinations support `require` to delay initialization until specific collector events fire. Use `require: ["consent"]` to prevent loading until consent is granted:

```
{
  "sources": {
    "session": {
      "package": "@walkeros/web-source-session",
      "config": { "require": ["consent"] }
    }
  },
  "destinations": {
    "ga4": {
      "package": "@walkeros/web-destination-gtag",
      "config": {
        "require": ["consent"],
        "consent": { "marketing": true }
      }
    }
  }
}
```

See [Destinations documentation](https://www.walkeros.io/docs/destinations.md) for all available options.

### Transformers[​](#transformers "Direct link to Transformers")

Transformers process events between sources and destinations. They validate, enrich, or redact events in the pipeline.

```
{
  "transformers": {
    "fingerprint": {
      "package": "@walkeros/server-transformer-fingerprint",
      "config": {
        "settings": { "format": true }
      }
    }
  }
}
```

**Configuration options:**

* **`package`** - The npm package (required for package-based steps, optional when using `code:`)
* **`code`** - Explicit import variable name (optional, auto-resolved)
* **`config`** - Transformer-specific configuration
* **`env`** - Environment-specific settings
* **`before`** - Pre-transformer chain (runs before this transformer's push)
* **`next`** - Next transformer in chain (omit to end chain)
* **`variables`** - Transformer-level variable overrides

**Chaining transformers:**

Link transformers together using `next`:

```
{
  "transformers": {
    "enrich": {
      "package": "@walkeros/transformer-enricher",
      "config": { "apiUrl": "https://api.example.com" },
      "next": "fingerprint"
    },
    "fingerprint": {
      "package": "@walkeros/server-transformer-fingerprint"
    }
  }
}
```

**Explicit chain control with arrays:**

For explicit control over the transformer chain order, use an array instead of a string. This bypasses the automatic chain resolution:

```
{
  "sources": {
    "http": {
      "package": "@walkeros/server-source-express",
      "next": ["fingerprint", "enrich", "redact"]
    }
  },
  "transformers": {
    "fingerprint": { "package": "@walkeros/server-transformer-fingerprint" },
    "enrich": { "package": "@walkeros/transformer-enricher" },
    "redact": { "package": "@walkeros/transformer-redact" }
  }
}
```

| Syntax                              | Behavior                                                          |
| ----------------------------------- | ----------------------------------------------------------------- |
| `"next": "fingerprint"`             | Walks chain via each transformer's `next` property                |
| `"next": ["fingerprint", "enrich"]` | Uses exact order specified, ignores transformer `next` properties |

**Connecting to sources and destinations:**

* **Source preprocessing**: Use `before` on a source for consent-exempt preprocessing (runs before the source's push)
* **Pre-collector chain**: Use `next` on a source to route events through transformers before the collector
* **Post-collector chain**: Use `before` on a destination to route events through transformers after the collector
* **Post-push chain**: Use `next` on a destination to process events after the destination push completes

```
{
  "sources": {
    "http": {
      "package": "@walkeros/server-source-express",
      "before": "decoder",
      "next": "fingerprint"
    }
  },
  "transformers": {
    "decoder": { "package": "@walkeros/transformer-decoder" },
    "fingerprint": { "package": "@walkeros/server-transformer-fingerprint" },
    "redact": { "package": "@walkeros/transformer-redact" },
    "auditLog": { "package": "@walkeros/transformer-audit" }
  },
  "destinations": {
    "analytics": {
      "package": "@walkeros/server-destination-gcp",
      "before": "redact",
      "next": "auditLog"
    }
  }
}
```

All chain fields (`before` and `next`) accept arrays for explicit chain control (see "Explicit chain control with arrays" above).

See [Transformers documentation](https://www.walkeros.io/docs/transformers.md) for available transformers and custom transformer guide.

### Connection rules[​](#connection-rules "Direct link to Connection rules")

Sources, transformers, collectors, and destinations connect in specific ways. This table summarizes every valid connection:

| From        | To          | Field                   | Notes                                      |
| ----------- | ----------- | ----------------------- | ------------------------------------------ |
| Source      | Transformer | `before` on source      | Consent-exempt preprocessing               |
| Source      | Transformer | `next` on source        | Pre-collector chain                        |
| Source      | Collector   | omit `next`             | Default: events go straight to collector   |
| Transformer | Transformer | `before` on transformer | Pre-transform enrichment                   |
| Transformer | Transformer | `next` on transformer   | Chain continues to next transformer        |
| Collector   | Transformer | `before` on destination | Post-collector chain                       |
| Collector   | Destination | omit `before`           | Default: events go straight to destination |
| Destination | Transformer | `next` on destination   | Post-push processing                       |

**Connections that are not allowed:**

* Source to source
* Source directly to destination (events must pass through the collector)
* Collector to source

#### Chain resolution[​](#chain-resolution "Direct link to Chain resolution")

The `next` and `before` fields on sources, transformers, and destinations all accept either a string or an array. The resolution behavior differs:

| Value                               | Behavior                                                          |
| ----------------------------------- | ----------------------------------------------------------------- |
| `"fingerprint"` (string)            | Walks `transformer.next` links until the chain ends               |
| `["fingerprint", "enrich"]` (array) | Uses the array as-is, ignoring each transformer's `next` property |

When walking a string chain, three edge cases apply:

1. **String with array `next`**: If `fingerprint.next` is `["a", "b"]`, the walker appends that array and stops. The final chain becomes `["fingerprint", "a", "b"]`.
2. **Missing target**: If a transformer name in the chain does not exist, that step is skipped and the event proceeds unchanged. If a string chain points to a nonexistent first transformer, the chain is empty and the event goes through without transformation.
3. **Circular reference**: Detected via a visited set and safely broken, with no infinite loop.

#### Pre-collector vs post-collector transformers[​](#pre-collector-vs-post-collector-transformers "Direct link to Pre-collector vs post-collector transformers")

All transformers live in a single `transformers` pool. Their position in the pipeline depends on which field references them:

```
[Source.before] → Source ──[next]──→ Pre-transformers ──→ Collector ──→ Post-transformers ──[before]──→ Destination ──[next]──→ Post-push
```

The same transformer can appear in both a pre-collector and a post-collector chain. For example, you might use `fingerprint` in a source's `next` chain and again in a destination's `before` chain. Each invocation runs independently.

```
{
  "sources": {
    "http": {
      "package": "@walkeros/server-source-express",
      "next": "fingerprint"
    }
  },
  "transformers": {
    "fingerprint": {
      "package": "@walkeros/server-transformer-fingerprint"
    },
    "enrich": {
      "package": "@walkeros/transformer-enricher"
    }
  },
  "destinations": {
    "analytics": {
      "package": "@walkeros/server-destination-gcp",
      "before": "enrich"
    }
  }
}
```

In this config, `fingerprint` runs before the collector (pre-chain) and `enrich` runs after the collector but before the `analytics` destination (post-chain).

#### Conditional routing[​](#conditional-routing "Direct link to Conditional routing")

Every chain field (`source.before`, `source.next`, `transformer.before`, `transformer.next`, `destination.before`, `destination.next`) accepts a `Route`. `Route` is recursive:

```
type Route = string | Route[] | RouteConfig;
```

A `string` names a transformer (or a path, see below). A `Route[]` runs each entry in order as a pipeline. A `RouteConfig` is a disjoint union: it sets **exactly one** of `next`, `one`, `many`, or none of them (pure gate that only filters by `match`). `match` is optional everywhere; omit it to always match.

##### Route operators[​](#route-operators "Direct link to Route operators")

A `RouteConfig` is a disjoint union. Pick the operator that matches the routing shape you need:

* `next`: single continuation. Optionally gated by `match`.
* `one`: first-match dispatch. Walk entries in order; the first whose `match` passes wins, and the main chain continues with that entry's `Route`.
* `many`: all-match terminal fan-out. Every matching entry spawns an independent flow that runs to its own exit. The main chain terminates at the `many` step. Restricted to pre-collector positions (`source.next`, `transformer.next`, `transformer.before`). Post-collector fan-out uses the destinations map.

First-match dispatch is the `one` operator:

```
{
  "sources": {
    "http": {
      "package": "@walkeros/server-source-express",
      "next": {
        "one": [
          {
            "match": { "key": "ingest.path", "operator": "prefix", "value": "/purchase" },
            "next": "purchase_parser"
          },
          { "next": "default_parser" }
        ]
      }
    }
  }
}
```

`one` entries are evaluated in order and the first matching `Route` wins. The trailing entry omits `match`, so it always matches and acts as the default branch. If no entry matches, the event passes through unchanged to the collector.

Terminal fan-out is the `many` operator. Use it when one inbound event needs to feed several independent processing branches (for example, splitting a webhook payload into per-vendor enrichment paths before the collector):

```
{
  "sources": {
    "http": {
      "package": "@walkeros/server-source-express",
      "next": {
        "many": [
          {
            "match": { "key": "ingest.path", "operator": "prefix", "value": "/purchase" },
            "next": "purchase_parser"
          },
          {
            "match": { "key": "ingest.path", "operator": "prefix", "value": "/signup" },
            "next": "signup_parser"
          }
        ]
      }
    }
  }
}
```

Every entry in `many` whose `match` passes runs as its own branch. The main chain stops at the `many` step, so each branch is responsible for its own continuation. If no entry matches, the event is dropped from the pre-collector pipeline.

To name and reuse a chain without writing code, declare a **path** transformer: a transformer entry with no `code` / `package`, just `before` / `next` / `cache`. The collector synthesizes a code-less passthrough so the named entry can be referenced from any `Route`:

```
{
  "transformers": {
    "purchase_parser": {
      "next": ["fingerprint", "enrich"]
    }
  }
}
```

#### Deferred activation with `require`[​](#deferred-activation-with-require "Direct link to deferred-activation-with-require")

Sources and destinations support `require` to delay initialization until a specific collector event fires. This is commonly used for consent-gated loading:

```
{
  "destinations": {
    "analytics": {
      "package": "@walkeros/web-destination-gtag",
      "config": {
        "require": ["consent"]
      }
    }
  }
}
```

The `analytics` destination will not initialize until a `"consent"` event is pushed to the collector. Until then, events are queued. This works identically for sources:

```
{
  "sources": {
    "session": {
      "package": "@walkeros/web-source-session",
      "config": {
        "require": ["consent"]
      }
    }
  }
}
```

tip

Combine `require` with `consent` on destinations for full consent management: `require` controls when the destination loads, while `consent` controls which events it receives. See the [Destinations](#destinations) section above for a combined example.

### Inline Code (without packages)[​](#inline-code-without-packages "Direct link to Inline Code (without packages)")

For simple one-liner logic, define sources, transformers, or destinations inline without creating a package.

Use `code` object instead of `package`:

**Inline Transformer:**

```
{
  "transformers": {
    "enrich": {
      "code": {
        "type": "enricher",
        "push": "$code:(event) => ({ ...event, data: { ...event.data, timestamp: Date.now() } })"
      },
      "config": {}
    }
  }
}
```

**Inline Destination:**

```
{
  "destinations": {
    "logger": {
      "code": {
        "type": "console-logger",
        "push": "$code:(event, context) => { context.logger.info(event.name, event.data); }"
      },
      "config": {}
    }
  }
}
```

**Code object properties:**

* **`push`** - The push function with `$code:` prefix (required)
* **`type`** - Optional instance type identifier
* **`init`** - Optional init function with `$code:` prefix

**Rules:**

* Use `package` OR `code`, never both
* `config` stays separate (same as package-based)
* `$code:` prefix outputs raw JavaScript at bundle time

### Collector[​](#collector "Direct link to Collector")

The collector processes events from sources and routes them to destinations:

```
{
  "collector": {
    "globals": {
      "environment": "production"
    },
    "consent": {
      "functional": true
    }
  }
}
```

**Options:**

* **`run`** - Whether to start the collector automatically (default: `true`)
* **`globals`** - Properties added to every event
* **`consent`** - Default consent state

See [Collector documentation](https://www.walkeros.io/docs/collector.md) for complete options.

### Web-specific options[​](#web-specific-options "Direct link to Web-specific options")

For browser bundles, you can configure the collector's window variable name via `config.settings`:

```
{
  "config": {
    "platform": "web",
    "settings": {
      "windowCollector": "walkerCollector"
    }
  }
}
```

**Properties:**

* **`windowCollector`** - Global variable name for collector instance (default: `"walkerOS"`)

The `window.elb` function is owned by the browser source: set `elb` in the browser source's `config.settings` to change its global name (default: `"elb"`). The former `windowElb` setting is deprecated; when set, its value is forwarded to the browser source's `settings.elb` with a warning.

## Multi-flow configuration[​](#multi-flow-configuration "Direct link to Multi-flow configuration")

For managing dev/staging/production flows in one file:

```
{
  "version": 4,
  "variables": {
    "defaultCurrency": "USD"
  },
  "flows": {
    "development": {
      "config": {
        "platform": "server",
        "bundle": {
          "packages": {
            "@walkeros/destination-demo": { "imports": ["destinationDemo"] }
          }
        }
      },
      "destinations": {
        "console": {
          "package": "@walkeros/destination-demo",
          "config": {
            "settings": { "name": "Dev Logger" }
          }
        }
      },
      "collector": {}
    },
    "production": {
      "config": {
        "platform": "server",
        "bundle": {
          "packages": {
            "@walkeros/server-destination-gcp": { "imports": ["destinationGCP"] }
          }
        }
      },
      "destinations": {
        "bigquery": {
          "package": "@walkeros/server-destination-gcp",
          "config": {
            "settings": {
              "projectId": "prod-project"
            }
          }
        }
      },
      "collector": {}
    }
  }
}
```

Build specific flows using the CLI:

```
# Build development flow
walkeros bundle config.json --flow development

# Build production flow
walkeros bundle config.json --flow production

# Build all flows
walkeros bundle config.json --all
```

### Cross-flow references with `$flow`[​](#cross-flow-references-with-flow "Direct link to cross-flow-references-with-flow")

Flows in the same file can reference each other's `config` block via `$flow.<name>.<path>`. The most common case is linking a web flow's API destination to a server flow's deployed URL:

```
{
  "version": 4,
  "flows": {
    "server": {
      "config": {
        "platform": "server",
        "url": "https://collect.example.com",
        "bundle": {
          "packages": { "@walkeros/server-source-express": {} }
        }
      },
      "sources": {
        "http": {
          "package": "@walkeros/server-source-express",
          "config": { "settings": { "path": "/collect", "port": 8080 } }
        }
      }
    },
    "web": {
      "config": {
        "platform": "web",
        "bundle": {
          "packages": {
            "@walkeros/web-source-browser": {},
            "@walkeros/web-destination-api": {}
          }
        }
      },
      "sources": {
        "browser": { "package": "@walkeros/web-source-browser" }
      },
      "destinations": {
        "api": {
          "package": "@walkeros/web-destination-api",
          "config": {
            "settings": { "url": "$flow.server.url" }
          }
        }
      }
    }
  }
}
```

Cross-flow refs read values from another flow's `config` block (`platform`, `url`, `settings.*`), keeping web and server flows in sync without duplication. The bundler resolves `$flow.server.url` to `https://collect.example.com` at build time. Validate is lenient (warns on missing values), bundle is strict and fails loudly if the referenced value is empty, so production builds never ship with an unresolved URL.

## Dynamic patterns[​](#dynamic-patterns "Direct link to Dynamic patterns")

Flow configurations support four dynamic patterns for reusable, environment-aware configs:

### `$var.name` - Config Variables[​](#varname---config-variables "Direct link to varname---config-variables")

Reference variables defined in `variables` for shared values across your config:

```
{
  "version": 4,
  "variables": {
    "currency": "EUR",
    "apiVersion": "v2"
  },
  "flows": {
    "default": {
      "config": { "platform": "web" },
      "destinations": {
        "api": {
          "package": "@walkeros/web-destination-api",
          "config": {
            "settings": {
              "endpoint": "https://api.example.com/$var.apiVersion/collect",
              "currency": "$var.currency"
            }
          }
        }
      }
    }
  }
}
```

Variables can be defined at three levels (higher specificity wins):

1. **Source/Destination level** - Highest priority
2. **Flow (Config) level** - Middle priority
3. **Setup level** - Lowest priority

### `$env.NAME` - Environment Variables[​](#envname---environment-variables "Direct link to envname---environment-variables")

Reference environment variables with optional defaults:

```
{
  "version": 4,
  "flows": {
    "default": {
      "config": { "platform": "web" },
      "destinations": {
        "ga4": {
          "package": "@walkeros/web-destination-gtag",
          "config": {
            "settings": {
              "ga4": { "measurementId": "$env.GA4_ID:G-DEMO123456" }
            }
          }
        }
      }
    }
  }
}
```

**Syntax:**

* `$env.GA4_ID` - Required, throws if not set
* `$env.GA4_ID:default` - Uses "default" if not set

Why only `$env` supports defaults

Environment variables are external and unpredictable - they might not be set in all environments. Config variables (`$var`) are explicitly defined, so a missing one indicates a configuration error.

### `$code:` - Inline JavaScript[​](#code---inline-javascript "Direct link to code---inline-javascript")

Embed JavaScript code directly in JSON config values:

```
{
  "destinations": {
    "api": {
      "package": "@walkeros/web-destination-api",
      "config": {
        "mapping": {
          "product": {
            "view": {
              "data": {
                "map": {
                  "item_id": {
                    "key": "data.id",
                    "fn": "$code:(value) => value.toUpperCase()"
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
```

The `$code:` prefix is stripped during bundling, outputting raw JavaScript:

```
// Bundler output
{
  item_id: {
    key: "data.id",
    fn: (value) => value.toUpperCase()
  }
}
```

**Use cases:**

* **`fn:` callbacks** - Transform values in mapping
* **`condition:` predicates** - Conditional event processing
* **Custom logic** - Any inline function or expression

**Syntax notes:**

* Multi-line code: Use JSON escapes (`\n`, `\"`)
* Scope: Same as bundled code (access to imports and variables)
* Errors: Caught at build time by TypeScript/esbuild

## Type hierarchy[​](#type-hierarchy "Direct link to Type hierarchy")

walkerOS uses a clear type hierarchy:

```
┌─────────────────────────────────────────────────────────────────┐

│  Flow.Json (config file)                                        │

│  ├── version: 4                                                 │

│  ├── variables?: { currency: "EUR" }                            │

│  └── flows:                                                     │

│       └── default: Flow                                         │

└─────────────────────────────────────────────────────────────────┘

                              │

                              │ CLI resolves $var, $env, $flow

                              ▼

┌─────────────────────────────────────────────────────────────────┐

│  Flow (resolved flow)                                           │

│  ├── config: { platform, url?, settings?, bundle? }             │

│  ├── sources: { ... }                                           │

│  ├── transformers: { ... }                                      │

│  ├── destinations: { ... }                                      │

│  ├── stores: { ... }                                            │

│  └── collector: { ... }                                         │

└─────────────────────────────────────────────────────────────────┘

                              │

                              │ CLI bundles and transforms

                              ▼

┌─────────────────────────────────────────────────────────────────┐

│  Collector.InitConfig (runtime)                                 │

│  Passed to startFlow() at runtime                               │

└─────────────────────────────────────────────────────────────────┘
```

* **`Flow.Json`** - Root config file format for CLI
* **`Flow`** - Single flow configuration (with optional `config`, `sources`, `destinations`, etc.)
* **`Flow.Config`** - Per-flow config block (`platform`, `url`, `settings`, `bundle`)
* **`Collector.InitConfig`** - Runtime type passed to `startFlow()`

## Complete example[​](#complete-example "Direct link to Complete example")

Here's a production-ready flow that accepts HTTP events and sends them to BigQuery:

```
{
  "version": 4,
  "flows": {
    "default": {
      "config": {
        "platform": "server",
        "bundle": {
          "packages": {
            "@walkeros/server-source-express": { "imports": ["sourceExpress"] },
            "@walkeros/server-destination-gcp": { "imports": ["destinationGCP"] },
            "@walkeros/destination-demo": { "imports": ["destinationDemo"] }
          }
        }
      },
      "sources": {
        "http": {
          "package": "@walkeros/server-source-express",
          "config": {
            "settings": {
              "path": "/collect",
              "port": 8080,
              "cors": true
            }
          }
        }
      },
      "destinations": {
        "bigquery": {
          "package": "@walkeros/server-destination-gcp",
          "config": {
            "settings": {
              "projectId": "my-analytics-project",
              "datasetId": "events",
              "tableId": "raw_events"
            },
            "mapping": {
              "page": {
                "view": {
                  "name": "page_view",
                  "data": {
                    "map": {
                      "page_title": "data.title",
                      "page_path": "data.path",
                      "timestamp": "timestamp"
                    }
                  }
                }
              },
              "product": {
                "view": { "name": "product_view" },
                "add": { "name": "add_to_cart" }
              }
            }
          }
        },
        "console": {
          "package": "@walkeros/destination-demo",
          "config": {
            "settings": {
              "name": "Debug Logger",
              "values": ["name", "data", "timestamp"]
            }
          }
        }
      },
      "collector": {
        "globals": {
          "environment": "production",
          "version": "1.0.0"
        }
      }
    }
  }
}
```

## Programmatic usage[​](#programmatic-usage "Direct link to Programmatic usage")

You can also use configuration programmatically with the `startFlow` function:

```
import { startFlow } from '@walkeros/collector';
import { sourceExpress } from '@walkeros/server-source-express';
import { destinationDemo } from '@walkeros/destination-demo';

const { collector, elb } = await startFlow({
  sources: {
    http: {
      ...sourceExpress,
      config: {
        settings: { path: '/collect', port: 8080 }
      }
    }
  },
  destinations: {
    console: {
      ...destinationDemo,
      config: {
        settings: { name: 'Logger' }
      }
    }
  },
});

// Collector is now running and ready to process events
```

See the [Collector documentation](https://www.walkeros.io/docs/collector.md) for complete API reference.

## Next steps[​](#next-steps "Direct link to Next steps")

* **[CLI](https://www.walkeros.io/docs/apps/cli.md)** - Learn how to bundle and test flows
* **[Docker](https://www.walkeros.io/docs/apps/docker.md)** - Deploy flows in containers
* **[Sources](https://www.walkeros.io/docs/sources.md)** - Explore available event sources
* **[Destinations](https://www.walkeros.io/docs/destinations.md)** - Configure analytics destinations
* **[Mapping](https://www.walkeros.io/docs/mapping.md)** - Transform events for destinations
