Skip to main content

Manage metafield definitions

Metafield definitions are schemas that specify the structure, type, and rules for metafields. Without definitions, metafields are untyped strings that can't be edited in the Shopify admin or be validated. This guide covers all aspects of managing definitions through both TOML configuration (for apps) and the GraphQL Admin API.


  • Your app can make authenticated requests to the GraphQL Admin API.
  • Your app has the appropriate access scopes for the owner type that you want to associate with the metafield definition. For example, write_products for product metafields, or write_customers for customer metafields.

Anchor to Creating definitionsCreating definitions

There are three ways to set up metafield definitions:

  • TOML: TOML configurations in shopify.app.toml create app-owned definitions. Your app maintains control while optionally allowing edits in the Shopify admin.
  • GraphQL: The GraphQL Admin API provides programmatic control for creating merchant-owned metafields (editable in the Shopify admin and accessible to all installed apps) and dynamically generating definitions based on user configuration.
  • Standard definitions: Enable Shopify's pre-defined definitions for common use cases. See Standard definitions for more details.

Anchor to TOML (app-owned) exampleTOML (app-owned) example

This example creates an app-owned metafield that tracks when products were last synchronized with an external system. Since the app controls the sync process, it uses an app's TOML configuration file to ensure that the definition is consistently deployed across all installations.

Step 1: Add the definition to your app's shopify.app.toml file.

[product.metafields.app.last_synced]
name = "Last Synced"
description = "When this product was last synchronized with external system"
type = "date_time"
access.admin = "merchant_read"

Step 2: Deploy the changes with your app.

shopify app deploy

Benefits of TOML:

  • Definitions are version-controlled as part of your app.
  • Automatic creation and updates on deploy.
  • Consistent across all shops - when you update your app's data structure, it deploys to every installation automatically.
  • The app maintains ownership.

Anchor to GraphQL Admin API exampleGraphQL Admin API example

These examples show how to create metafield definitions using GraphQL. The first creates a merchant-owned definition that all apps can access. The second creates an app-owned definition that only your app controls.

# POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
# Headers: X-Shopify-Access-Token: {merchant_token}

mutation CreateMerchantOwnedDefinition {
metafieldDefinitionCreate(
definition: {
namespace: "product_details"
key: "warranty_info"
name: "Warranty Information"
description: "Product warranty details and coverage"
type: "multi_line_text_field"
ownerType: PRODUCT
access: {
storefront: PUBLIC_READ
}
}
) {
createdDefinition {
id
namespace
key
}
userErrors {
field
message
}
}
}
# POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
# Headers: X-Shopify-Access-Token: {app_token}

mutation CreateAppOwnedDefinition {
metafieldDefinitionCreate(
definition: {
namespace: "$app" # app-reserved namespace
key: "warranty_info"
name: "Warranty Information"
description: "Product warranty details and coverage"
type: "multi_line_text_field"
ownerType: PRODUCT
access: {
admin: MERCHANT_READ_WRITE
storefront: PUBLIC_READ
}
}
) {
createdDefinition {
id
namespace
key
}
userErrors {
field
message
}
}
}

Key differences:

  • Merchant-owned: Use any non-reserved namespace (like product_details). This provides full control in the Shopify admin—no access.admin needed. Only access.storefront is used to control customer visibility.
  • App-owned: Use the reserved $app namespace. The app controls the definition. Use access.admin to grant merchant write permissions.

Anchor to When to use GraphQL vs TOMLWhen to use GraphQL vs TOML

Use TOML when:

  • Your app needs fixed, known fields (for example, tracking numbers, warranty dates)
  • The structure is consistent across all installations
  • Fields are core to your app's functionality
  • You want a version-controlled, declarative configuration

Use GraphQL when:

  • Merchants define their own custom fields through your app's UI
  • Field structure varies per merchant or changes frequently
  • Building form builders, CMS-like tools, or field managers
  • You're creating merchant-owned fields that other apps can access

Anchor to Dynamic definition creation exampleDynamic definition creation example

This example shows how to programmatically create definitions based on user input, such as in a field manager app where custom fields are configured through your app's UI.

Your app would collect field configuration (via a form or UI), validate the input, construct the variables object, and then execute the mutation. This enables the creation of custom fields through your app's interface without editing code or configuration files.

POST https://{shop}.myshopify.com/api/{api_version}/graphql.json

GraphQL mutation

mutation CreateDynamicField($input: MetafieldDefinitionInput!) {
metafieldDefinitionCreate(definition: $input) {
createdDefinition {
id
name
namespace
key
type { name }
}
userErrors {
field
message
code
}
}
}

Variables

{
"input": {
"name": "Return Policy",
"namespace": "custom",
"key": "return_policy",
"description": "Store's return policy for this product",
"type": "multi_line_text_field",
"ownerType": "PRODUCT",
"validations": [
{
"name": "max_length",
"value": "1000"
}
],
"access": {
"storefront": "PUBLIC_READ"
}
}
}

Anchor to Querying definitionsQuerying definitions

Use GraphQL to find existing definitions and check their capabilities.

Query all definitions by resource type:

GraphQL

POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
query {
metafieldDefinitions(first: 100, ownerType: PRODUCT) {
edges {
node {
id
namespace
key
name
type { name }
access { admin storefront }
}
}
}
}

Search definitions by name or namespace:

GraphQL

POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
query {
metafieldDefinitions(
first: 20
ownerType: PRODUCT
query: "warranty"
) {
edges {
node {
id
name
namespace
key
type { name }
}
}
}
}

Find a specific definition by namespace and key:

GraphQL

POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
query {
metafieldDefinitions(
first: 1
ownerType: PRODUCT
namespace: "product_details"
key: "warranty_info"
) {
edges {
node {
id
name
namespace
key
type { name }
access { admin storefront }
}
}
}
}
Tip

Query the metafieldDefinitionTypes field to see which validations each type supports, or check the supportedValidations field when querying existing definitions.


Anchor to Updating definitionsUpdating definitions

Only specific fields can be updated after creation:

FieldCan updateMethod
Name and descriptionYesTOML or GraphQL
ValidationsYes (with limits)TOML or GraphQL
Access permissionsYesTOML or GraphQL
TypeNoCan't change
Namespace/keyNoImmutable
Owner typeNoCan't migrate

The following example shows how to update a definition's name, description, and access permissions using the metafieldDefinitionUpdate mutation:

GraphQL

POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
mutation {
metafieldDefinitionUpdate(
definition: {
id: "gid://shopify/MetafieldDefinition/1234567890"
name: "Updated Name"
description: "Updated description"
access: { storefront: PUBLIC_READ }
}
) {
updatedDefinition { id name }
userErrors { field message }
}
}
Caution

Tightening validations may fail if existing metafields violate the new constraint.

To change a namespace/key:

  1. Create a new definition with the desired namespace/key
  2. Copy the existing metafield values to the new namespace/key
  3. Update your app code, extensions, and integrations to reference the new namespace/key
  4. Test thoroughly with both definitions active to ensure everything works
  5. Delete the old definition once migration is complete

This approach enables safe, zero-downtime migration by allowing you to test with both the old and new metafields active before removing the old one.


Anchor to Deleting definitionsDeleting definitions

To remove definitions via TOML:

  • Step 1: Remove the definition from the file.
  • Step 2: Deploy the change with your app, using:
shopify app deploy

Alternatively, use the metafieldDefinitionDelete mutation:

GraphQL

POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
mutation {
metafieldDefinitionDelete(
id: "gid://shopify/MetafieldDefinition/1234567890"
deleteAllAssociatedMetafields: true
) {
deletedDefinitionId
userErrors { field message }
}
}

Set deleteAllAssociatedMetafields to true to delete all metafield values along with the definition, or false to only delete the definition while preserving existing values.


Access is controlled by the definition namespace and optional parameters.

For app-owned metafields:

  • Merchants can always read all metafields in their store.
  • The access.admin setting controls whether merchants can edit values in the Shopify admin UI.
  • Use "merchant_read_write" to allow merchant editing of app-owned metafields in the Shopify admin.

For merchant-owned metafields:

  • Merchants always have full control.
  • The access.storefront setting controls customer visibility.

Anchor to Standard definitionsStandard definitions

Shopify provides pre-defined standard metafield definitions for common use cases like product descriptions, ISBN numbers, and care instructions. These definitions use reserved namespace/key combinations (such as descriptors.subtitle or facts.isbn) that ensure interoperability across themes, apps, and the Shopify ecosystem.

Standard definitions are Shopify-owned with predefined access controls that vary by definition. Apps can read and write values, but cannot modify the definition itself.

Query available standard definitions using the standardMetafieldDefinitionTemplates query:

GraphQL

POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
query {
standardMetafieldDefinitionTemplates(first: 50) {
edges {
node {
id
name
namespace
key
type { name }
ownerTypes
}
}
}
}

Enable standard definitions using TOML configuration or the standardMetafieldDefinitionEnable mutation. This example enables the subtitle and ISBN standard definitions for products:

shopify.app.toml

[product.metafields]
standard_metafields = ["descriptors.subtitle", "facts.isbn"]

[product_variant.metafields]
standard_metafields = ["descriptors.subtitle"]
# Enable subtitle standard metafield on product
mutation {
standardMetafieldDefinitionEnable(
id: "gid://shopify/StandardMetafieldDefinitionTemplate/1",
ownerType: PRODUCT
) {
createdDefinition {
name
key
namespace
description
}
}
}

# Enable ISBN standard metafield on product
mutation {
standardMetafieldDefinitionEnable(
id: "gid://shopify/StandardMetafieldDefinitionTemplate/3",
ownerType: PRODUCT
) {
createdDefinition {
name
key
namespace
description
}
}
}

# Enable subtitle standard metafield on product variant
mutation {
standardMetafieldDefinitionEnable(
id: "gid://shopify/StandardMetafieldDefinitionTemplate/1",
ownerType: PRODUCTVARIANT
) {
createdDefinition {
name
key
namespace
description
}
}
}

For more about standard definitions, see the standard definitions list.


Understanding common errors helps you implement proper error handling and provide better user experiences. Most errors occur during definition creation or updates when validations, permissions, or naming conflicts arise.

ErrorCauseSolution
"Definition for this namespace and key already exists"Duplicate namespace/keyQuery existing definitions first
"Type <invalid_type> is not a valid type"Invalid type nameCheck available types
"Validation <validation_name> is not supported for type <type_name>"Wrong validation for typeQuery supportedValidations or check validations guide
"App does not have permission to modify this definition"Not app-ownedOnly app-owned definitions can be modified by apps

Following these practices helps ensure maintainable, scalable metafield implementations that work well across development, staging, and production environments. Good naming and planning prevent migration headaches and help make your metafields easier for teams to understand and use.

  • Use descriptive namespaces: shipping.settings rather than custom
  • Add validations gradually: Start loose, tighten as needed
  • Test in development first: Verify before production
  • Document for your team: Maintain a schema reference
  • Cache definition IDs: Avoid repeated queries
  • Batch related operations: Create multiple definitions together


Was this page helpful?