Migration guides
Migrating from pre-release packages to v1
- Migrate in stages
- Project and CLI
- Project definitions
- Tests
- JavaScript SDK
- Upgrade the SDK and modulesBreaking
- Factory and options renamedBreaking
- Operations are asynchronousBreaking
- Datafiles merge by defaultSoft breaking
- Modules use a focused APIBreaking
- Diagnostics replace custom loggingBreaking
- Delivery and lifecycleChanged
- Pixel scripts are disabled by defaultBreaking
- React
- Verification checklist
This guide covers the intentional breaking changes between Eventvisor 0.x packages and the stable v1 release. It includes project definitions, CLI workflows, JavaScript and React applications, and custom modules.
Migrate in stages#
Treat the project and its consuming applications as two parts of the migration:
- Prepare applications: upgrade the SDK and modules, update custom module code, and deploy application changes that can consume the current datafile.
- Upgrade the Eventvisor project: update the CLI, add Targets, migrate test expectations, then lint, test, build, and deploy the v1 datafiles.
Generated datafiles still use schema version 1. The v1 SDK can consume existing 0.x datafiles, which makes it possible to upgrade applications before changing the project output.
Do not assume that a 0.x SDK understands v1-only definitions or corrected runtime semantics. Upgrade every consuming application before deploying datafiles that depend on the new sampling, validation failure, condition, effect, or module behaviour described below.
Review sampling before rollout
Sampling evaluation was corrected in v1. Any project using sample should compare the old and new behaviour in a staging application before publishing v1 datafiles. A configured percentage now represents the documented percentage.
Project and CLI#
Upgrade the CLI Breaking#
Update the project dependency:
$ npm install --save @eventvisor/cli@1Eventvisor v1 CLI development and execution require Node.js 24 or newer.
Targets replace tag datafiles Breaking#
In 0.x, every configured tag generated a datafile such as eventvisor-tag-web.json. In v1, tags are selection metadata and only named Targets generate normal datafiles.
Create at least one Target in every project or Set:
module.exports = { tags: ["web", "backend"],};datafiles/├── eventvisor-tag-web.json└── eventvisor-tag-backend.jsondescription: Web applicationtag: webdescription: Backend servicestag: backenddatafiles/├── eventvisor-web.json└── eventvisor-backend.jsonUpdate application URLs and deployment scripts to use the new filenames. Targets can also include and exclude entity keys with glob-like patterns. Eventvisor retains referenced attributes, destinations, effects, quarantine destinations, and other runtime dependencies.
Selective commands accept repeatable --target and --tag options. When both are present, the filters use AND semantics.
State directory configuration removed Breaking#
The unused statesDirectoryPath configuration property and states/ entity type have been removed. Effect state remains supported and lives inside each effect definition.
Remove statesDirectoryPath from eventvisor.config.js. No effect state migration is required.
Reusable Schemas New#
Shared JSON Schema structures can now live in schemas/ and be referenced by events, attributes, nested properties, and array items:
description: Stable identifiertype: stringminLength: 1description: Order completedtype: objectproperties: orderId: schema: identifierrequired: - orderIdReferences are resolved and inlined during linting, code generation, and datafile building. SDK datafiles do not contain a separate Schema collection.
Sets and promotions New#
Sets let one repository contain independent definition trees. They can model release environments or other isolated projects:
module.exports = { sets: true, promotionFlows: [ { from: "development", to: "staging" }, { from: "staging", to: "production" }, ],};Use Promotions to preview and apply dependency-aware changes between Sets. Existing projects do not need to enable Sets.
Built in parsers moved to their own package Internal#
YAML and JSON parsing now comes from @eventvisor/parsers, which is installed through the CLI. Existing parser: "yml" and parser: "json" configuration continues to work.
Custom parsers must now implement both parse and stringify. The stringify function is needed for promotion and other editorial writes.
Catalog development workflow Changed#
Running the Catalog without a subcommand now exports, serves, watches project files, and reloads connected browser pages:
$ npx eventvisor catalogUse catalog export for a one-time static export and catalog serve to serve an existing export. Browser routing is the default. Pass --hash-router only when a static host cannot serve index.html for application routes.
The v1 Catalog adds reusable Schemas, Targets, dependency usage, expanded matrix tests, entity history, and Set switching.
New inspection commands New#
The CLI now includes commands for inspecting and exercising a project:
$ npx eventvisor list event$ npx eventvisor info event page_view$ npx eventvisor find-usage attribute userId$ npx eventvisor simulate page_view --value='{"url":"https://example.com"}'$ npx eventvisor benchmark page_view -n 1000000Use find-usage --unused-attributes --unused-schemas --unused-destinations to find known unused definitions.
Project definitions#
Events must resolve to objects Breaking#
Every event must now resolve to type: object, either directly or through a reusable Schema. Add the type where old definitions relied on an implicit object shape:
description: Page viewtype: objectproperties: url: type: stringWhen an event shape changes incompatibly, create a new event key. Eventvisor deliberately does not add a separate event version field.
Object properties are strict Breaking#
Object payloads reject properties that are not declared in properties. During gradual adoption, opt out explicitly at the appropriate object boundary:
type: objectadditionalProperties: trueRemove additionalProperties: true after all producers follow the declared contract.
Validation failure policies New#
Invalid events use the project default, which is drop. During a migration you can deliver the original payload with validation details:
module.exports = { onValidationFailure: "deliverWithWarning",};Or quarantine invalid events to one destination:
onValidationFailure: action: quarantine destination: invalidEventsAn event-level policy overrides the project default. Quarantine bypasses normal destinations and effects.
Sampling follows the documented scale Fix#
Sampling percentages and ranges now correctly use the 0 through 100 scale with up to three decimal places. For example, percentage: 10 selects approximately ten per cent of bucket keys.
The stable MurmurHash bucketing algorithm and bucket assignments have not changed. The v1 fixes are in evaluation around those buckets:
- a percentage now compares against the correct 100,000 bucket scale
- a range is start inclusive and end exclusive
- conditional sample arrays use the first matching rule
- a missing or empty bucket key fails closed
Pre-release sampling did not consistently honour these rules. Measure representative traffic with simulate, project tests, and a staging application before rollout.
not uses implicit AND semantics Breaking#
Direct children of not are treated as an implicit AND. This expression means “not all of these conditions match”:
not: - attribute: country operator: equals value: NL - attribute: plan operator: equals value: premiumTo preserve the pre-release “none of these match” behaviour, wrap the children in one explicit or group before deploying v1:
not: - or: - attribute: country operator: equals value: NL - attribute: plan operator: equals value: premiumThe explicit group has the same meaning in both 0.x and v1 SDKs, which helps during a gradual application rollout.
Empty and, or, and not groups are rejected by linting and fail closed at runtime.
Portable conditions Breaking#
Regular expressions use a portable subset shared by JavaScript and Java SDKs. Only unique g, i, m, and s flags are accepted. Lookaround, named or noncapturing groups, backreferences, inline modes, atomic groups, and possessive quantifiers are rejected.
Values used by before and after must be complete ISO 8601 date and time strings with a timezone. Invalid regular expressions, dates, and semantic versions fail closed.
Existence checks treat null as defined. Membership operators consistently support string, number, boolean, and null values.
Sources and transforms are type-safe Changed#
Direct source, attribute, state, effect, payload, and lookup fields accept one source or a nonempty ordered array. A definition cannot set several direct source fields at once.
Transform options are validated according to their transform type. The append transform is now available. For increment and decrement with a target, the current target value is the numeric input and value is the operand.
Unsafe object paths and values that cannot be represented safely in transport payloads are rejected.
Effect errors stop by default Breaking#
In 0.x, a failed effect step could continue unless continueOnError was explicitly false. In v1, a failed handler stops the remaining steps by default.
Set continueOnError: true only where later steps are safe and meaningful after a failure:
steps: - handler: audit.record continueOnError: true - handler: notification.sendEffect handlers that track another Eventvisor event should use the module API track() function. It carries the active effect chain and prevents recursive effect cycles.
Tests#
Pipeline acceptance has a dedicated expectation Breaking#
expectedToContinue has been replaced by expectedToBeTracked:
expectedToBeValid: trueexpectedToContinue: trueexpectedToBeValid: trueexpectedToBeTracked: trueexpectedToBeValid checks the event payload schema. expectedToBeTracked checks whether required attributes, validation policy, conditions, and sampling accepted the event through the complete governance pipeline.
Assertions must test behaviour Breaking#
Every test spec needs at least one assertion. Each assertion needs a meaningful action and expectation. Filters that match no specs or assertions now fail instead of reporting a false passing result.
The unused event assertion at field and unsupported expectedToBeBatched and expectedBatchedCount fields have been removed. Use expectedBody, expectedBodies, and assertAfter for destination behaviour.
Matrix assertions New#
Assertions can define a matrix whose Cartesian product is executed by both the tester and Catalog:
event: page_viewassertions: - description: tracks on ${{ device }} in ${{ country }} matrix: device: [mobile, desktop] country: [NL, DE] track: device: ${{ device }} withAttributes: country: ${{ country }} expectedToBeTracked: trueA matrix must contain at least one key and every key must contain at least one value.
JavaScript SDK#
Upgrade the SDK and modules Breaking#
$ npm install --save @eventvisor/sdk@1Upgrade every installed @eventvisor/module-* package to the v1 major at the same time. React applications should also install @eventvisor/react@1.
Factory and options renamed Breaking#
import { createInstance, type InstanceOptions,} from "@eventvisor/sdk";const options: InstanceOptions = { datafile };const eventvisor = createInstance(options);import { createEventvisor, type EventvisorOptions,} from "@eventvisor/sdk";const options: EventvisorOptions = { datafile };const eventvisor = createEventvisor(options);Use the exported Eventvisor type when passing the instance through application code.
DatafileReader, managers, evaluators, the logger factory, and other internal classes are no longer public. Import only from the package root.
Operations are asynchronous Breaking#
The old fire-and-forget methods and separate async aliases have become one Promise based API:
eventvisor.setAttribute("userId", "123");await eventvisor.setAttributeAsync("userId", "123");eventvisor.track("page_view", payload);await eventvisor.trackAsync("page_view", payload);await eventvisor.setAttribute("userId", "123");await eventvisor.track("page_view", payload);track, setAttribute, removeAttribute, setDatafile, removeModule, flush, and close are asynchronous. Public operations are serialized in call order, including calls made before readiness.
Datafiles merge by default Soft breaking#
In 0.x, setDatafile() replaced the active datafile. In v1, it merges incoming attributes, events, destinations, and effects by default:
await eventvisor.setDatafile(additionalDatafile);Pass true to retain the old replacement behaviour:
await eventvisor.setDatafile(nextDatafile, true);The method accepts a parsed object or JSON string. Parse failures keep the active datafile and report a diagnostic containing Could not parse datafile. The datafile_set event now contains { replaced }.
Modules use a focused API Breaking#
Rename Module to EventvisorModule and registerModule() to addModule():
import type { Module } from "@eventvisor/sdk";const module: Module = { name: "warehouse", async transport(options, deps) { deps.logger.info("sending"); },};eventvisor.registerModule(module);import type { EventvisorModule } from "@eventvisor/sdk";const module: EventvisorModule = { name: "warehouse", setup(api) { api.reportDiagnostic({ level: "info", code: "warehouse_ready", message: "Warehouse module is ready", details: {}, }); }, async transport(options, api) { // Send options.payload. },};const remove = eventvisor.addModule(module);await remove?.();The module API exposes getRevision, onDiagnostic, reportDiagnostic, and cycle-safe track. Modules can implement setup, flush, and close lifecycle functions. Duplicate names and lifecycle failures are reported through diagnostics.
Diagnostics replace custom logging Breaking#
The logger option and public createLogger API have been removed. Use logLevel, onDiagnostic, or a later diagnostic subscription:
const eventvisor = createEventvisor({ datafile, logLevel: "warn", onDiagnostic(diagnostic) { observability.capture(diagnostic); },});const unsubscribe = eventvisor.onDiagnostic(handleDiagnostic);Diagnostics contain a stable code, level, message, details, and optional module or error information. Error diagnostics also emit the SDK error event.
Delivery and lifecycle Changed#
Selected destination transports start in parallel and receive the active datafile revision. track() waits for each selected transport attempt to settle, but transport modules decide whether that attempt means immediate delivery or queue acceptance.
Use await eventvisor.flush() to ask queueing modules to attempt buffered work. close() waits for readiness, flushes modules, closes their resources, and clears SDK event listeners and diagnostic subscriptions.
The new @eventvisor/module-http provides bounded batching and retries. The new @eventvisor/module-beacon handles browser page lifecycle delivery on a best effort basis.
Pixel scripts are disabled by default Breaking#
The Pixel module still injects ordinary markup, but ignores script elements unless application code opts in:
createPixelModule({ allowScripts: true, nonce: () => window.__cspNonce,});Only enable scripts when the datafile publishing path is trusted and protected. Review the security guide and apply a restrictive Content Security Policy.
React#
React hooks now use explicit Eventvisor names:
import { useInstance, isReady, useEventvisor,} from "@eventvisor/react";import { useEventvisorInstance, useEventvisorReady, useEventvisor,} from "@eventvisor/react";useEventvisorAttribute and useEventvisorAttributes provide reactive attribute values. Hooks now throw a clear error outside EventvisorProvider, reset readiness when the provider instance changes, and return stable bound operations for an unchanged instance.
Verification checklist#
Before deploying v1 datafiles:
- Upgrade every consuming SDK and module package.
- Rewrite direct multi-child
notgroups with an explicitorwhen preserving the 0.x meaning. - Review every sampling rule against the corrected percentage and range behaviour.
- Add at least one Target to every project or Set.
- Update datafile URLs from
eventvisor-tag-<tag>.jsontoeventvisor-<target>.json. - Remove
statesDirectoryPathand obsolete test fields. - Update custom modules and React hook imports.
- Run project linting and tests.
- Build every Target and inspect the generated file list.
- Exercise representative events with
simulateand a staging application.
$ npx eventvisor lint$ npx eventvisor test$ npx eventvisor buildFor Set projects, repeat focused checks for every release lane before promotion or deployment.

