Shopify Checkout UI Extensions: Migrate to Preact and Web Components
To migrate Shopify checkout UI extensions, you now have to move from the legacy React and Remote UI model to Preact and Polaris web components on a current API version. Shopify’s own engineering team says deployments that include older extension versions are blocked from October 1, 2026, a date that has now passed. This guide covers what to change, the 64KB bundle budget and the problems Shopify hit in its own migration. Checked against Shopify’s migration guide, the Checkout Blocks engineering write-up and a Shopify staff reply.

What Changed for Checkout UI Extensions
Extensions on API version 2025-10 and later use Polaris web components by default. If your extension still targets an older version, Shopify’s guide says you need to adopt web components as part of the upgrade. In practice that means custom s-* elements instead of React components, a global shopify object instead of callback parameters, and Preact instead of React.
- Unmigrated extensions keep running. A Shopify staff member says extensions that are not migrated keep working for merchants, but you cannot deploy them anymore.
- One old extension can block the app. Per the same reply, every UI extension in an app must be on a supported API version before the app can be deployed.
- The date. Shopify’s engineering post says deployments that include extension versions earlier than 2026-01 are blocked starting October 1, 2026, and that 2025-07 is being sunset.
One detail does not line up. The changelog quoted in the community thread names API versions 2025-07 or earlier, while the engineering post says earlier than 2026-01. Rather than guess which wording applies to you, move every extension to a current version. The migration guide itself uses 2026-04.
Step 1: Update the API Version and the CLI
Set the version in each extension’s shopify.extension.toml and upgrade the CLI.
api_version = "2026-04"npm install -g @shopify/cliStep 2: Move Metafields to appMetafields
As of 2026-04 the metafields property is deprecated. The guide gives these replacements.
- Read values through
shopify.appMetafieldsinstead ofshopify.metafields,useMetafield()oruseMetafields(). - Declare every metafield your extension needs with
[[extensions.metafields]]in the TOML file. - Write cart metafields with the
updateCartMetafieldandremoveCartMetafieldchange types.useApplyMetafieldsChange(),MetafieldUpdateChangeandMetafieldRemoveChangeare deprecated. - To copy cart metafields onto orders, the app needs the
write_ordersscope and a matching order metafield definition with thecart_to_order_copyablecapability.
Metafield declarations are also about to get stricter. See our guide to the owner_type requirement coming in API 2027-01, and our explainer on metafields vs metaobjects if the data model itself needs a second look.
Step 3: Adopt Preact and Web Components
This step applies when you upgrade from a version earlier than 2025-10. The guide lists these changes.
- Dependencies: use
preact(^10.10.x),@preact/signals(^2.3.x) and@shopify/ui-extensions(2026.4.x), and remove the React packages. - TypeScript: add an extension-level
tsconfig.jsonwithjsxset toreact-jsx,jsxImportSourceset topreact, andincludecovering./srcand./shopify.d.ts. - Types: run
shopify app dev. It generatesshopify.d.tsin the extension directory and adds the globalshopifyobject. - Entry point: import
@shopify/ui-extensions/preactand render your component intodocument.bodyfrom an exported function. - APIs: call them on the global object, for example
await shopify.applyAttributeChange(...). - Hooks: import hooks such as
useAttributeValuesfrom@shopify/ui-extensions/checkout/preact, or prefer the global object for simple reads and writes. - Components: replace React components with custom elements such as
<s-stack>,<s-text-field>,<s-button>and<s-checkbox>. The guide links a per-component upgrade page for roughly 60 legacy components.
The sketch below shows the shape of an entry point. It is our illustration of the pattern the guide describes, so compare it with the template that shopify app generate extension gives you before relying on it.
import '@shopify/ui-extensions/preact';
import { render } from 'preact';
export default function extension() {
render(<Extension />, document.body);
}
function Extension() {
return (
<s-stack gap="base">
<s-text>Hello from a web component extension</s-text>
</s-stack>
);
}Stay Under the 64KB Bundle Budget
Shopify’s engineering post says the 2026-01 remote-dom CLI enforces a hard 64KB gzip limit per extension bundle. Their Checkout Blocks extensions started around 100KB to 112KB gzipped, so they had to cut roughly half. These are the changes that paid off.
- Switching from React to Preact removed
react-reconciler, saving about 89KB. This was the biggest win. - Replacing
liquidjswith an in-house Liquid parser saved about 73KB raw, roughly 13KB gzipped against about 22KB. - Replacing
dayjswith a small date utility saved about 12KB. - Aliasing React to Preact kept
markdown-to-jsxworking, because it uses no hooks and only importscreateElement,FragmentandcloneElement.
Shopify reports transferred bundle sizes down 40% to 85% across the five extensions, and Extension Load Time down 8% at the median and 7% at the 90th percentile, weighted by checkout volume.
Problems Shopify Hit in Its Own Migration
- Duplicate IDs. Preact’s
useId()produced identical IDs for multiple instances of the same extension. That broke thecommandForandidpairing for web components, so overlays opened the wrong modal. It was their one production rollback. The fix was a hook that generates random, instance-unique IDs. - Text alignment.
textAlignhad been removed fromParagraphandHeading, which broke centered layouts. - Checkbox labels.
s-checkboxaccepted only a plain string label, which blocked inline links until a label slot was added upstream.
Our Analysis: How to Plan the Migration
Inventory first, then migrate. Because one old extension can block a whole app deploy, list every checkout and customer account extension across your apps before touching code. Our suggestion is to treat the oldest one as the critical path.
Measure bundle size on day one. A 64KB hard limit is a pass or fail check, not a tuning target. Build a trivial extension first and see what your dependencies cost, then decide which libraries to replace.
Ship one extension at a time. Shopify released at most one extension per day, lowest risk first, with success and failure metrics in place beforehand. That is a sound pattern for any team.
Use tooling, then review. Shopify published an AI toolkit and upgrade guides for this migration, and its own team used an agent for mechanical conversion. Our AI Toolkit vs Dev MCP comparison explains where that fits. Review the output, especially IDs, alignment and accessibility.
FAQ about Checkout UI Extension Migration
Will live extensions stop working for merchants? According to a Shopify staff reply, unmigrated extensions keep working for merchants, but you cannot deploy new versions.
Which API version should I target? Shopify’s guide uses 2026-04. Versions 2025-10 and later already use web components by default.
Do I have to use Preact? For upgrades from before 2025-10, the guide tells you to adopt Preact and web components together.
Does this affect POS extensions? The sources we read cover checkout and customer account UI extensions. We could not confirm from them whether POS extensions follow the same date, so check Shopify’s documentation for your extension type.

