Upgrade notes for partners

This document describes the two changes in this release that can reach an existing app: FlexGrid 3.0.0 takes over the latest dist-tag from FlexGrid 2.x, and the supported toolchain moves to Node.js 24 and pnpm 11.

Neither change is a deprecation. You can stay on FlexGrid 2.x deliberately, and it keeps receiving fixes until approximately October 2026. To avoid upgrading by accident, you must pin the 2.x range. See Staying on your current setup for more information.

The following table lists each change and whether any action is required:

ChangeAction required?
The @roku-sdk/flex-grid 3.0.0 package now owns latestYes, if your range is latest, *, or >=2: pin ^2.0.0, or the install upgrades you across a major version
The 2.x stable dist-tag changed from latest-2 to maintenance-2xYes, if you install by dist-tag
The supported runtime is now Node.js 24 and pnpm 11Not immediately: installs still succeed on Node 20 with a warning. See the toolchain section for more information about the two cases that fail
Every @roku-sdk/* package now declares engines.node as >=24.0.0No: a dependency's engines field is advisory
FlexGrid 2.x cell KeyDelegates receive "OK" instead of "ok"Yes, if a delegate compares key against "ok": use RemoteKey.Select. The type checker does not catch this

Staying on your current setup

This section describes how to keep an existing app on FlexGrid 2.x and what you get by doing so.

1. Pinning FlexGrid to the 2.x range (required)

The @roku-sdk/flex-grid package publishes two major versions under one package name. Before this release, latest pointed at 2.x; it now points at 3.0.0, which has breaking changes. Any range that can resolve a 3.x version picks one up on your next pnpm update or on a fresh pnpm install without a lockfile.

The following example shows the ranges that resolve to 3.x and the range that stays on 2.x:

// These ranges now resolve to 3.x
"@roku-sdk/flex-grid": "latest"
"@roku-sdk/flex-grid": "*"
"@roku-sdk/flex-grid": ">=2.0.0"

// This range stays on 2.x and keeps receiving 2.x fixes
"@roku-sdk/flex-grid": "^2.0.0"

A caret range keeps you on 2.x: ^2.0.0 cannot resolve a 3.x version no matter which major version holds latest; therefore, it stays stable when latest changes owner, now and in the future.

If your lockfile already pins an exact 2.x version, a plain pnpm install does not move you. You must fix the range anyway because the next pnpm update upgrades you.

2. Updating the dist-tag if you install by tag (required)

The SDK renamed the 2.x stable tag so that a bare pnpm add @roku-sdk/flex-grid installs 3.x. The following table lists the old and new tags:

ChannelOld 2.x tagNew 2.x tag3.x tag
stablelatest-2maintenance-2xlatest-3, and plain latest
rcrc-2rc-2rc-3, and plain rc
devdev-2dev-2dev-3, and plain dev

The following example shows the old command and the new command:

# No longer resolves
pnpm add @roku-sdk/flex-grid@latest-2

# Resolves to the 2.x stable release
pnpm add @roku-sdk/flex-grid@maintenance-2x

Only the stable tag changed. The rc-2 and dev-2 tags are unchanged.

3. Node.js and pnpm (recommended, not required)

You can keep building on Node 20 and pnpm 10 for now. See Toolchain for more information about when that stops being true. SDK continuous integration (CI) no longer covers Node 20; therefore, you should treat Node 20 support as best-effort.

What you get by staying on 2.x

Staying on 2.x gives you bug fixes and security patches until approximately October 2026, but no new features, which land on 3.x only. The 2.x line never moves back onto the latest tag.

Moving to FlexGrid 3

This section describes the four steps to move an app from FlexGrid 2.x to 3.x. Peer dependencies are identical between 2.x and 3.x (@roku-sdk/common, components, interfaces, navigation, runtime, solid, all ^2.0.0); therefore, this is a FlexGrid-only upgrade, and no other @roku-sdk/* package has to move with it.

Step 1: Upgrading the toolchain

FlexGrid 3.x declares engines.node >= 24.0.0. You should install Node 24 and pnpm 11 as described under Toolchain.

Step 2: Bumping the range

Change the range in package.json:

"@roku-sdk/flex-grid": "^3.0.0"

Then install the new version:

pnpm install

The import specifier does not change; it is still @roku-sdk/flex-grid.

Step 3: Working through the breaking changes

The package's BREAKING_CHANGES.md file lists every change with before and after code, and its src/MIGRATION.md file has the plugin-internals rename table. The following table lists the changes that can affect an app:

ChangeWhat to do
createZoomFocusPlugin() removedWrap the templates that should scale: withZoomFocus(MyCell, { focusedScale, unfocusedScale }) from @roku-sdk/flex-grid/zoom-focus. Zoom is now set per template when the registry is built; therefore, isZoomEnabled does not have any equivalent
Select key is "OK", not "ok"In a cell KeyDelegate, match RemoteKey.Select (re-exported from @roku-sdk/flex-grid). forwardKeyEvent("ok", …) is ignored; use "OK". The SDK removed the select alias; the key now bubbles to the enclosing boundary
onKeyEvent config option removedTo intercept movement, use a cell KeyDelegate. For region hand-off, use onEdgeReached and setFocus. For back, options, and play, use the onUnhandledKey option of an enclosing FocusBoundary
Focus-highlight config keys movedrenderFocusHighlight, focusHighlightVisible, focusHighlightLayer are now options on createFocusHighlightPlugin from @roku-sdk/flex-grid/focus-highlight, passed via plugins
createPool takes an options objectcreatePool(cfg, { perf, debugViewport, idPrefix, gridKey }). The removed positional scaleMode and scaleTweenDuration arguments came before perf; therefore, a stale call can still compile while meaning something else. You should check every call site
Flat GridPluginInternals fields deletedCustom plugins only: fields moved under rows / focus / scroll / layers. Apps that pass only the built-in plugin factories do not need any change
computeScrollYGroup renamed to computeScrollYCustom vertical focus strategies only. The SDK does not provide a fallback; a method that you do not rename silently loses its scroll math. The built-in fixedFocusStrategy and floatingFocusYStrategy already use the new name
EngineConfig per-row geometry must be an accessorDirect createFlexGridEngine callers only: rowHeights: () => heights. Going through createFlexGrid / defineFlexGrid still accepts plain arrays
The node tree of a pooled cell is one level shallowerAffects only SceneGraph snapshot tests and findNode-style traversal from a cell root. The public API does not change
onEdgeReached top and bottom now fire at the first and last focusable rowGrids with empty leading or trailing rows now fire the callback where they previously consumed the key press without firing it

Step 4: Verifying

You should run your unit tests first because a snapshot or key-delegate test catches the "ok" to "OK" change and the shallower pooled node tree immediately. Then check focus visuals and select behavior on a real device.

Rolling back

You can set the range back to ^2.0.0 and reinstall. 2.x remains published and installable for the whole maintenance window.

Toolchain: Node.js 24 and pnpm 11

The following commands install the supported toolchain:

nvm install 24 && nvm use 24
npm install -g [email protected]

You must upgrade Node before pnpm, not after. pnpm 11 requires Node 22.13 or later and does not work below it: on Node 20 it aborts with ERR_UNKNOWN_BUILTIN_MODULE: No such built-in module: node:sqlite before running any command. If you are staying on Node 20 for now, you must stay on pnpm 10 as well; the two old versions work together, but pnpm 11 on Node 20 does not work at all.

Does this break my existing app today?

This section describes when the toolchain change affects an existing app. Usually it does not. The engines.node field of a dependency is advisory in both npm and pnpm. The engineStrict setting of pnpm defaults to false; therefore, installing @roku-sdk/* on Node 20 prints a warning and proceeds.

Two cases fail the install:

  1. Your own package.json declares "node": ">=24.0.0". pnpm always enforces the project's own engines field, regardless of engineStrict. Apps that you scaffold with rk create after this release carry that field; therefore, a new scaffold on Node 20 fails with ERR_PNPM_UNSUPPORTED_ENGINE. Apps that you scaffolded earlier declare >=20.0.0 and are unaffected until you copy the new value in.
  2. You set engineStrict: true in your own pnpm-workspace.yaml or .npmrc. That setting extends enforcement to dependencies, and every @roku-sdk/* package now asks for Node 24.

Beyond installation, SDK CI now tests on Node 24 only; therefore, Node 20 support is best-effort from here. You should plan the upgrade rather than treating the warning as permanent.

pnpm 10 → 11 configuration migration

This section applies only if your own repository carries pnpm configuration. pnpm 11 changed where it reads two settings:

  • pnpm 11 no longer reads the pnpm.overrides and pnpm.auditConfig keys in package.json. You must move them to top-level overrides and auditConfig keys in pnpm-workspace.yaml. Leaving them in package.json disables them silently, without reporting a warning or an error, and your overrides are not applied.
  • The allowBuilds setting replaces onlyBuiltDependencies and ignoredBuiltDependencies. pnpm 11 fails pnpm install when a dependency has a build script that is neither allowed nor explicitly denied, and because pnpm run now performs a dependency-status check first, that failure surfaces on every script you run.

An app that you create with rk create already has the pnpm-workspace.yaml file with these settings. An app that predates 2.15, or one that you copied from the SDK's examples, must have a decision for each of the four packages in an SDK app's tree that have an install script. The following file shows a decision for each package:

# pnpm-workspace.yaml
allowBuilds:
    '@roku-sdk/tooling': true   # postinstall marks the bundled hermesc executable
    '@parcel/watcher': false    # native binary ships as an optional platform dependency
    esbuild: false              # native binary ships as an optional platform dependency
    unrs-resolver: false        # native binary ships as an optional platform dependency

overrides:
    esbuild: '>=0.28.1'

The SDK repository's pnpm-workspace.yaml file is an example of both settings.

Troubleshooting

The following table lists common symptoms, their causes, and fixes:

SymptomCauseFix
No matching version found for @roku-sdk/flex-grid@latest-2The 2.x stable tag was renamedUse @maintenance-2x, or switch to the ^2.0.0 range
FlexGrid compiles but focus zoom stops working after an install you did not intend as an upgradeAn unpinned range resolved 3.0.0, where zoom is a template wrapperPin ^2.0.0, or complete the 3.x migration
ERR_PNPM_UNSUPPORTED_ENGINEYour own package.json requires Node 24Upgrade to Node 24, or lower your app's own engines.node
ERR_UNKNOWN_BUILTIN_MODULE: No such built-in module: node:sqlitepnpm 11 running on Node 20Upgrade Node first: pnpm 11 needs Node 22.13 or later
EBADENGINE / Unsupported engine warning, install succeedsA dependency wants Node 24 and you are on Node 20Advisory only. Upgrade when convenient
pnpm overrides stopped applying after moving to pnpm 11pnpm.overrides in package.json is no longer readMove them to pnpm-workspace.yaml
pnpm install fails with ERR_PNPM_IGNORED_BUILDSpnpm 11 requires an explicit allowBuilds decisionAdd each listed package to allowBuilds in pnpm-workspace.yaml (see the migration notes)

Related documentation


Did this page help you?