Skip to main content

Upgrade to the latest API version and Polaris web components

This guide explains the steps you need to take to migrate your checkout UI extensions to the latest API version, including metafield APIs.

Info

If you're upgrading from a version earlier than 2025-10, you'll need to adopt Polaris web components. Versions 2025-10 and later use web components by default.


Anchor to Step 1: Update API versionStep 1: Update API version

Update the API version to the latest version in shopify.extension.toml (for example, 2026-04).

shopify.extension.toml

api_version = "2026-04"

[[extensions]]
name = "your-extension"
handle = "your-extension"
type = "ui_extension"

# Contents of your existing file...

Anchor to Step 2: Migrate to cart metafieldsStep 2: Migrate to cart metafields

As of the 2026-04 API version, the metafields property is deprecated. Use shopify.appMetafields to access values that you previously read using shopify.metafields or the useMetafield() and useMetafields() hooks.

Use cart metafields and update them using MetafieldUpdateCartChange and MetafieldRemoveCartChange.

The useApplyMetafieldsChange() hook is deprecated, as well as the MetafieldRemoveChange and the MetafieldUpdateChange inputs to the applyMetafieldChange method. See metafields API for more details.

Info
To persist cart metafields to orders, ensure your app has the write_orders scope and create a matching order metafield definition with the cart_to_order_copyable capability. For a step-by-step walkthrough, see the add a field to checkout tutorial.

Anchor to Request metafields in your extension TOMLRequest metafields in your extension TOML

Request metafields that your extension needs access to in your extension configuration using [[extensions.metafields]]. See configurations for more details.

shopify.extension.toml

[[extensions.metafields]]
namespace = "my-namespace"
key = "gift-requested"

Use shopify.appMetafields to read cart metafields. To write data, use cart metafield change types updateCartMetafield and removeCartMetafield.

package.json

tsx

import "@shopify/ui-extensions/preact";
import { render } from "preact";
import { useMetafield } from "@shopify/ui-extensions/checkout/preact";

export default function extension() {
render(<Extension />, document.body);
}

function Extension() {
const giftRequested = useMetafield({
namespace: "my-namespace",
key: "gift-requested",
});

return (
<s-checkbox
checked={giftRequested?.value === "true"}
onChange={onCheckboxChange}
label="Include a free gift with my order"
/>
);

async function onCheckboxChange(event) {
const isChecked = event.target.checked;

if (isChecked) {
await shopify.applyMetafieldChange({
type: "updateMetafield",
namespace: "my-namespace",
key: "gift-requested",
valueType: "string",
value: "true",
});
} else {
await shopify.applyMetafieldChange({
type: "removeMetafield",
namespace: "my-namespace",
key: "gift-requested",
});
}
}
}

Anchor to Step 3: Adopt web components and PreactStep 3: Adopt web components and Preact

The following sections apply only if you're upgrading from a version earlier than 2025-10. If you're already using web components and Preact, you don't need to make any changes.

Anchor to Adjust package dependenciesAdjust package dependencies

For API versions 2025-10 and later, Shopify recommends Preact for UI extensions. Update your package.json file to specify the latest dependencies and re-install them.

package.json

New dependencies with Preact

{
"dependencies": {
"preact": "^10.10.x",
"@preact/signals": "^2.3.x",
"@shopify/ui-extensions": "2026.4.x"
}
}

Anchor to TypeScript configurationTypeScript configuration

Get full IntelliSense and auto-complete support by adding a config file for your extension at extensions/{extension-name}/tsconfig.json. You don't need to change your app's root tsconfig.json file.

tsconfig.json

New tsconfig.json

{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "preact",
"target": "ES2020",
"checkJs": true,
"allowJs": true,
"moduleResolution": "node",
"esModuleInterop": true
},
"include": ["./src", "./shopify.d.ts"]
}

Anchor to Upgrade the Shopify CLIUpgrade the Shopify CLI

The new Shopify CLI adds support for building with web components.

The shopify app dev command runs your app and also generates a shopify.d.ts file in your extension directory, adding support for the new global shopify object.

Support new global shopify object

CLI

# Upgrade to latest version of the CLI
npm install -g @shopify/cli

# Run the app to generate the type definition file
shopify app dev

Anchor to Optional ESLint configurationOptional ESLint configuration

If your app is using ESLint, update your configuration to include the new global shopify object.

.eslintrc.cjs

module.exports = {
globals: {
shopify: 'readonly',
},
};

Instead of accessing APIs from a callback parameter, access them from the global shopify object. Here's an example of migrating the applyAttributeChange API call.

Preact

New API calls in Preact

import '@shopify/ui-extensions/preact';
import {render} from 'preact';

export default function extension() {
render(<Extension />, document.body);
}

function Extension() {
return (
<s-checkbox
onChange={onCheckboxChange}
label="Include a complimentary gift"
/>
);
}

async function onCheckboxChange(event) {
const isChecked = event.target.checked;

const result =
await shopify.applyAttributeChange({
type: 'updateAttribute',
key: 'includeGift',
value: isChecked ? 'yes' : 'no',
});

console.log(
'applyAttributeChange result',
result,
);
}

If you had previously been using React hooks, you can continue using them by importing those same hooks from a new Preact-specific package. Here's an example of migrating the useAttributeValues hook:

Preact

New hooks in Preact

import '@shopify/ui-extensions/preact';
import {render} from 'preact';

import {useAttributeValues} from '@shopify/ui-extensions/checkout/preact';

export default function extension() {
render(<Extension />, document.body);
}

function Extension() {
const [includeGift] = useAttributeValues([
'includeGift',
]);
return (
<s-checkbox
checked={includeGift === 'yes'}
onChange={onCheckboxChange}
label="Include a complimentary gift"
/>
);
}

async function onCheckboxChange(event) {
const isChecked = event.target.checked;

const result =
await shopify.applyAttributeChange({
type: 'updateAttribute',
key: 'includeGift',
value: isChecked ? 'yes' : 'no',
});

console.log(
'applyAttributeChange result',
result,
);
}
Info

For hooks that perform simple read or write operations, we recommend that you use the shopify global object instead. Some Preact hooks take parameters and are provided as convenience wrappers to make it easier to perform common operations without writing your own logic. These hooks are documented on the individual API reference pages in Target APIs.

Anchor to Migrate to web componentsMigrate to web components

Web components are exposed as custom HTML elements. Update your React or JavaScript components to custom elements.

Preact

New components in Preact

/* eslint-disable react/self-closing-comp */
import '@shopify/ui-extensions/preact';
import {render} from 'preact';

export default function extension() {
render(<Extension />, document.body);
}

function Extension() {
return (
<s-stack direction="inline" gap="base">
<s-text-field label="Gift message"></s-text-field>
<s-button variant="primary">Save</s-button>
</s-stack>
);
}

Anchor to Mapping legacy components to web componentsMapping legacy components to web components


Was this page helpful?