Skip to content
Apexify.jsDocs
Apexify.js version v5.4.5

Advanced / Migration V6.Mdx · migration

Migration to Apexify.js 6

Current Apexify.js 6.0.0 documentation for Migration to Apexify.js 6.

apexify.jsRuntime: nodeCURRENTSince 6.0.0

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.

Change6.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 policyThere 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/26Older 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 exportsInternal lib-next/*, dist/*, and other source/deep paths have no compatibility guarantee. Use only documented package exports.
historically unbounded registries/fan-out → finite admission limitsThere 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 subclassesDo 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:

SOURCEtext
text
Node 22.x | 24.x | 26.xnpm >= 10

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:

SOURCEtypescript
typescript
Studio
import { ApexPainter } from "apexify.js";import type { CanvasConfig, SceneRenderInput } from "apexify.js";import type { VideoPipelineLayer } from "apexify.js/types";

CommonJS remains supported:

SOURCEjavascript
javascript
Studio
const { ApexPainter } = require("apexify.js");

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:

SOURCEtypescript
typescript
Studio
await painter.outPut(buffer);

It still works as a deprecated compatibility alias, but new code should use:

SOURCEtypescript
typescript
Studio
await painter.toOutput(buffer);

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:

SOURCEtypescript
typescript
Studio
await painter.use(plugin);

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.

SOURCEtypescript
typescript
Studio
import { ApexifyResourceLimitError } from "apexify.js"; try {  await renderJob();} catch (error) {  if (error instanceof ApexifyResourceLimitError) {    console.error(error.limit, error.maximum, error.actual);  }}

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:

SOURCEtypescript
typescript
Studio
configureApexifyRuntime({  network: {    trustedNetworkAccess: true,    allowedHosts: ["media.internal.example"],  },});

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:

SOURCEtext
text
APEXIFY_FFMPEG_PATHAPEXIFY_FFPROBE_PATH

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.

SurfaceCurrent default
renderScene, renderSceneToGIF, renderSceneToVideoFramesresolve
templatesresolve during template render
SceneBuilder.render()do not resolve unless enabled
imperative create/chart/GIF/video helpersdo not resolve unless enabled
batch() / chain()do not resolve unless enabled

For explicit imperative preprocessing:

SOURCEtypescript
typescript
Studio
const resolved = painter.prepareForRender(config);

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:

TERMINALbash
bash
$ npm cinpm test

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.

Next steps