Advanced / Migration V6.Mdx · migration
Migration to Apexify.js 6
Current Apexify.js 6.0.0 documentation for Migration to Apexify.js 6.
This guide covers migration from older 5.x-era usage to the current 6.0.0 package. It does not describe the separate future Phase 15+ engine roadmap.
Compatibility-window summary
Phase 13 requires changed behavior to state its compatibility status explicitly rather than leaving callers to infer it. Phase 14 independently re-audited those contracts and tightened remaining resource/error paths without adding a second compatibility mode.
| Change | 6.0 compatibility status |
|---|---|
outPut(buffer) → toOutput(buffer) | outPut() remains available in 6.0.0 as a deprecated compatibility alias. No removal release is committed here; migrate new and maintained code to toOutput() now. Any future removal requires an explicit release/migration notice. |
non-awaited painter.use(plugin) → await painter.use(plugin) | There is no synchronous compatibility guarantee in 6.0.0. The method is asynchronous because plugin installation may be asynchronous; callers that depend on installed APIs must await it. |
| permissive private-network fetching → explicit trusted-network policy | There is no legacy permissive compatibility mode. Private/local access requires trustedNetworkAccess: true plus an explicit host allowlist. |
| Node 18/20-or-older execution → Node 22/24/26 | Older Node majors are outside the 6.0.0 supported runtime window. Upgrade the application runtime before adopting staged 6.0.0. |
| deep/source imports → package exports | Internal lib-next/*, dist/*, and other source/deep paths have no compatibility guarantee. Use only documented package exports. |
| historically unbounded registries/fan-out → finite admission limits | There is no unbounded compatibility mode. Assets, plugins, fonts, unique in-flight image decodes, and template layout collections/fan-out are governed by the central runtime limits. |
generic runtime errors → structured ApexifyError subclasses | Do not branch on historical generic Error.message text. Use concrete Apexify error classes/codes and documented metadata. |
The sections below show the previous and current forms, why each change exists, and what action callers should take.
1. Upgrade the runtime first
Apexify.js 6 supports:
If the application is still on Node 18/20 or older, upgrade and run your test suite before adopting Apexify.js 6.
2. Use public package exports only
Supported imports:
CommonJS remains supported:
Do not migrate old deep/source imports by guessing new dist paths. lib-next/*, dist/*, and internal modules are not public API.
3. Prefer toOutput()
Older code may use:
It still works as a deprecated compatibility alias, but new code should use:
The painter constructor type controls this conversion; normal raster creation/render methods continue to produce Buffer-based results (with createCanvas() returning CanvasResults).
4. Await plugin installation
Current contract:
plugin.install(host) may be asynchronous. Installations are serialized, same-name installed/pending duplicates reject, and ApexPainter.use() resolves only after installation completes.
If older code called painter.use(plugin) without awaiting it, fix that ordering. Code that immediately consumes APIs registered by the plugin can otherwise race installation.
Plugin state is also resource-governed in the final 6.0.0 release candidate: API registrations, installed/pending names, and the transactional rollback journal have finite admission bounds. A plugin that attempts unbounded unique registrations can therefore receive ApexifyResourceLimitError rather than growing process state indefinitely.
5. Account for runtime validation and limits
Apexify.js 6 enforces bounded runtime policy across canvas, image, scene, templates, assets, plugins, fonts, GIF, audio, video, batch, network, and related high-cost APIs.
Handle ApexifyResourceLimitError as a deliberate rejected workload rather than assuming every historically accepted dimension/frame/collection count will still execute.
Use configureApexifyRuntime() only to set limits your deployment can actually sustain.
Final Phase 14 hardening applies maxCollectionItems to caller-controlled persistent/transient admission state, including asset/plugin/font registries, unique in-flight decoded-image work, and template layout child collections. Template flex/grid measurement also uses a worker pool capped by maxBatchConcurrency instead of launching one active measurement promise per child.
6. Use structured runtime errors
Apexify.js 6 runtime/public failure contracts use the ApexifyError hierarchy. Common classes include ApexifyInputError, ApexifyConfigError, ApexifyResourceLimitError, ApexifyRemoteFetchError, ApexifyDecodeError, ApexifyProcessError, ApexifyExternalServiceError, ApexifyAssetError, and ApexifyPluginError.
Do not migrate code by matching exact historical generic error-message strings. Prefer instanceof, the stable error code, and documented fields such as resource-limit metadata. Preserve cause for internal diagnostics but do not expose raw causes/process stderr/paths to untrusted clients.
7. Remote URLs are deny-by-default for private networks
Remote media now goes through a shared SSRF/network policy. Public HTTP(S) resources remain supported, but loopback/private/link-local/reserved/non-public targets are blocked by default and redirects are revalidated.
If your application intentionally fetches a private host, configure both:
Do not enable trusted network access globally just to restore old permissive behavior.
8. FFmpeg and temp configuration
Video features still require FFmpeg/ffprobe. Custom binary paths should use runtime/session configuration or:
Temporary media root uses APEXIFY_TEMP_DIR as a compatibility configuration path after explicit/runtime settings. Temp retention is off by default; APEXIFY_RETAIN_TEMP_FILES=true is debug-only.
9. Credentials are explicit
Apexify.js contains no fallback Imgur credentials. Configure the required IMGUR_* environment values or pass credentials explicitly to painter.output.url().
External remove-background integration likewise requires an explicit API key.
If an old deployment relied on credentials committed in source or historical fallbacks, rotate those credentials before migration.
10. Asset-resolution behavior
Do not assume $asset references resolve everywhere automatically.
| Surface | Current default |
|---|---|
renderScene, renderSceneToGIF, renderSceneToVideoFrames | resolve |
| templates | resolve during template render |
SceneBuilder.render() | do not resolve unless enabled |
| imperative create/chart/GIF/video helpers | do not resolve unless enabled |
batch() / chain() | do not resolve unless enabled |
For explicit imperative preprocessing:
11. Scenes/templates are validated composition contracts
Scene rendering always validates. A historical SceneRenderOptions.validate compatibility field does not disable mandatory validation.
Templates preserve native whole-placeholder values such as 0, false, and ""; defaults are nullish-oriented. Visibility/insertions/overrides/assets/layout are resolved deterministically before final scene validation.
Review code that previously depended on mutation of input objects: scene/template/asset paths use copy/snapshot semantics in current 6.0 behavior.
12. Test ESM/CJS/TypeScript from the actual artifact
The package CI verifies documentation examples against the packed .tgz, not only source-tree imports. For an application migration, do the same basic release check in a clean install/CI environment:
If you publish an internal wrapper around Apexify.js, test both the module format and types your consumers actually use.
13. What you should not migrate to yet
The current package does not ship the later roadmap's scoped @apexify/* runtime family, browser realtime renderer, React/Next adapters, Render IR/ARS, native animation engine, AI assistant, or distributed renderer.
Do not rewrite working Apexify.js 6 code around those future APIs before they exist in a released package.