Shopify app metafields and metaobjects 


Shopify metafields provide a means to expand Shopify's data model by storing additional information on various resources such as orders, products, customers, and the shop itself. They are commonly utilized in custom and public app development to enhance the functionality and user experience of Shopify apps.

While metafields are valuable for app development, working with them can be challenging for developers. The data is stored in a separate resource known as the "metafield object" on Shopify's end, whereas developers typically prefer the data to be directly associated with the resource they are extending. Moreover, Shopify's API rate limits can add complexity to the process of navigating across these additional resources.

To simplify the developer experience, Gadget offers a streamlined solution that enables fast synchronization, querying, and mutation of Shopify metafields within the backend of the app. This feature provides developers with efficient tools to manage metafields, reducing the complexities associated with working with metafields and improving the overall development workflow.

Storing metafield data in Gadget 

Gadget allows you to store metafield data directly on any of the following Shopify resources: articles, blogs, collections, customers, orders, pages, products, and shop.

To do this, you must first copy the desired resource to your Gadget backend. Go to the Connections screen and pick the desired scopes and models (e.g. the read_products scope and the Product model), and connect to a store.

Once you have the desired model in your Gadget backend, click on Add Field to decorate the model with the additional metafield values. Name your field and select an appropriate type for the incoming data. To start the metafield import, you also need to click the Store data from Shopify Metafield box.

The required fields to set up a metafield on a Shopify Model

You now need to register your metafield's Namespace. Enter the Namespace that is used for your metafield in the Shopify Store, then click Register Namespace. Gadget will then register for webhooks on the entered Namespace.

The namespace for a metafield is registered

Once you get a message stating that the Namespace registrations are complete, you can enter the key for your metafield and select the correct metafield type.

Here's an example of what the form looks like when we try to teach Gadget to store a metafield capturing each product variant's weight under the Namespace "gadget_app" and key "spiciness":

A completed Shopify metafield setup in Gadget

Your Gadget app is now set up to store the data directly on this model. You can go back to your Connections page and sync to pull in metafield data. Once the metafield data is synced to your Gadget app, you can query or mutate metafield values using Gadget Actions.

Querying metafields 

Gadget's approach to metafields offers two key advantages:

  1. Fetching data: You can retrieve metafield values alongside the records they are associated with in a single query. This simplifies the data retrieval process and reduces the number of API requests needed.

  2. Range queries: Gadget allows you to perform range queries directly on the metafield values. This enables you to apply filters, comparisons, or other conditions on the metafield values, providing more flexibility in data retrieval operations.

Gadget's metafield implementation facilitates efficient querying of metafield data alongside corresponding records and supports range queries for more advanced filtering and comparison operations.

Metafield query examples 

Here's an example of a range query being run on “spiciness”, a metafield stored on the Shopify Product, in order to fetch products that have a spiciness rating of greater than 5:

1query {
2 shopifyProducts(
3 filter: { spiciness: { greaterThan: 5 } }
4 sort: { spiciness: Ascending }
5 ) {
6 edges {
7 node {
8 title
9 id
10 spiciness
11 handle
12 }
13 }
14 }

Writing to metafields 

To mutate and sync metafield values in Gadget, you need to define the mutation logic in code. This is done by writing code within your action functions that Gadget executes when the API is triggered.

Metafield writing examples 

Here's an example of a Run function added to the update action of a Shopify Product model that sends the metafield information to Shopify:

2 * Action code for update on Shopify Product
3 * @param { import("gadget-server").UpdateShopifyProductActionContext } context - Everything for running this action, like the api client, current record, params, etc.
4 */
5export default async function run({ api, record, params, connections }) {
6 if (record.changed("title")) {
7 await connections.shopify.current?.graphql(
8 `mutation updateAMetafield($metafields: [MetafieldsSetInput!]!) {
9 metafieldsSet(metafields: $metafields) {
10 metafields {
11 id
12 value
13 }
14 }
15 }`,
16 {
17 metafields: [
18 {
19 key: "a_metafield",
20 namespace: "test321",
21 ownerId: `gid://shopify/Product/${}`,
22 type: "single_line_text_field",
23 value: record.title + " as a metafield!",
24 },
25 ],
26 }
27 );
28 }

This will only update the metafield value in Shopify! If you have registered the metafield on a Gadget model, the webhook that fires after the metafield is updated in Shopify will update the metafield value in Gadget.

We have an example of a more dynamic metafield update available as a gist on Github.


Metaobjects are similar to metafields, but they don't need to be tied to a Shopify resource. A metaobject definition can take any shape - metaobject fields are made up of groups of metafield types and can include references to Shopify resources, such as Orders or Products, or even references to other metaobjects!

Metaobjects can be created in the Shopify admin or using the metaobject API. Created metaobjects can be accessed directly in Liquid, using the Storefront API, or in the Admin API.

Metaobjects in Gadget 

To read or write metaobjects you need to add the Metaobject and Metaobject Definitions scopes when setting up or editing your Shopify connection.

It's important to note that:

  • The metaobjects API is available in API version 2023-01 and above
  • There are no models to import for metaobjects
  • Webhooks for metaobjects do not exist!

If you want to sync metaobject data from Shopify to Gadget, you will need to do so manually:

  • Create custom models in Gadget that match your metaobject definitions used to store the metaobject data
  • An action that can be triggered manually, on a schedule, or as part of some other action (ie. store install) that manually fetches metaobjects stored in Shopify. Note that you will need to deal with Shopify rate limits and add retry logic yourself.

Metaobject definitions 

You can use Shopify's GraphQL API to read, create, update, and delete metaobject definitions.

You can use your Gadget app's current Shopify connection to call these APIs to add or make changes to metaobject definitions on a merchant's store. For example, if you wanted to store some information about bikes (their style, model name, year, and a reference to the product record they pertain to), you would simply run the following code snippet:

1const metaobjectCreateMutation = `
2 mutation metaobjectDefinitionCreate($definition: MetaobjectDefinitionCreateInput!) {
3 metaobjectDefinitionCreate(definition: $definition) {
4 metaobjectDefinition {
5 name
6 type
7 }
8 userErrors {
9 field
10 message
11 }
12 }
13 }
14 `;
16// define a metaobject that can be used to store information for bicycles
17const createMetaobjectDefinition = await connections.shopify.current.graphql(
18 metaobjectCreateMutation,
19 {
20 definition: {
21 access: {
22 storefront: "PUBLIC_READ",
23 },
24 capabilities: {
25 publishable: {
26 enabled: true,
27 },
28 },
29 description: "Model information for bikes",
30 displayNameKey: "model",
31 fieldDefinitions: [
32 {
33 description: "Style of bike",
34 key: "style",
35 name: "Style",
36 type: "single_line_text_field",
37 required: true,
38 },
39 {
40 description: "Bike model name",
41 key: "model",
42 name: "Model",
43 type: "single_line_text_field",
44 required: true,
45 },
46 {
47 description: "Model year",
48 key: "year",
49 name: "Year",
50 type: "number_integer",
51 validations: {
52 name: "min",
53 value: "1950",
54 },
55 required: true,
56 },
57 {
58 description: "Bike product reference",
59 key: "bike_ref",
60 name: "Product reference",
61 type: "product_reference",
62 required: true,
63 },
64 ],
65 name: "Bike",
66 type: "bike",
67 },
68 }

Querying metaobjects 

You can utilize the metaobject API in Gadget to query actual instances of metaobjects. By using the Shopify connection established in Gadget, you can create instances of a specific metaobject, such as a bike metaobject. It's important to note that you need to have a corresponding metaobject definition in place before creating instances of the metaobject.

1const metaobjectSeedDataMutation = `
2 mutation metaobjectCreate($metaobject: MetaobjectCreateInput!) {
3 metaobjectCreate(metaobject: $metaobject) {
4 metaobject {
5 handle
6 }
7 userErrors {
8 field
9 message
10 }
11 }
12 }`;
14// add a new instance of my "bike" metaobject
15const createMetaobjectSeedData = await connections.shopify.current.graphql(
16 metaobjectSeedDataMutation,
17 {
18 metaobject: {
19 type: "bike",
20 handle: "kona-dew-plus-2015",
21 capabilities: {
22 publishable: {
23 status: "ACTIVE",
24 },
25 },
26 fields: [
27 {
28 key: "style",
29 value: "hybrid",
30 },
31 {
32 key: "model",
33 value: "Dew Plus",
34 },
35 {
36 key: "year",
37 value: "2015",
38 },
39 {
40 key: "bike_ref",
41 value: "gid://shopify/Product/7965217390872",
42 },
43 ],
44 },
45 }

You can also use the metaobjects query to read metaobject data. The following example uses the metaobject type field to fetch instances of a "bike" metaobject:

1await connections.shopify.current.graphql(
2 `query GetMetaobjects($type: String!) {
3 metaobjects(type: $type) {
4 fields {
5 key
6 reference
7 type
8 value
9 }
10 id
11 type
12 displayName
13 }
15 { type: "bike" }

References to metaobjects 

Even though metaobjects are stored independently of Shopify resources, Shopify also allows you to make associations between a metaobject and existing resources, such as products or orders, through metaobject references.

Metaobject references are stored on records as metafields and contain a reference to the metaobject. To capture this relationship in Gadget, you need to add a new metafield to a Shopify model in Gadget and select the "Metaobject reference" type. This field will then contain a reference to the metaobject in Shopify.