Skip to main content

About metafields

Shopify includes built-in data models like products, customers, and orders. Metafields extend these models by letting you add custom data to any Shopify resource.

You can use metafields to add warranty information to products, track customer lifetime value, store fulfillment notes on orders, link related products, trigger Shopify Flow automations, or power backend processes. This flexibility lets you extend Shopify's data model for specialized features and business logic.

Info

Metafields add individual custom fields to specific Shopify resources. Need to create standalone objects with multiple related fields? Use metaobjects instead.


Want to skip ahead? Choose a path based on what you're building:


Anchor to What are metafields?What are metafields?

Metafields are key-value pairs with the following components:

  • Identifier: A combination of namespace and key (for example, custom.warranty_info). Namespaces are logical containers that not only provide organization and prevent naming conflicts, they establish ownership.
  • Value: The data being stored.
  • Type: Defines the kind of value (such as text, number, date, or reference) and how the value is interpreted. See available types.

Anchor to Metafield definitionsMetafield definitions

Before creating a metafield, you will create a metafield definition. Metafield definitions establish data schemas that enable type validation, Shopify admin integration, query filtering, access control, and performance optimization.

Note

Shopify provides pre-built "standard" definitions for common use cases like ISBN numbers, product ingredients, and care instructions. Using standard definitions helps ensure interoperability across the Shopify ecosystem and saves you from defining schemas for well-known data types. Explore standard metafield definitions.

Ownership determines access and control. When creating metafields, you choose between two ownership models:

Ownership TypePurposeNamespace
App-ownedApp-managed data for internal logic, configuration, and workflowsUse reserved namespace $app (GraphQL) or app (TOML)
Merchant-ownedMerchant-managed data shared across all appsUse any non-reserved namespace, such as custom

Additional ownership types:

  • Shopify-reserved: Metafields with Shopify-controlled namespaces and structures, including those typically prefixed with reserved namespace shopify-- and standard definitions. Shopify controls the structure, but the metafields are typically merchant-owned.
  • App-data: A special type of app-owned metafield tied to your app installation (not to products, customers, or orders) and completely hidden from the Shopify admin. See App-data metafields for details.

Anchor to App-owned metafieldsApp-owned metafields

App-owned metafields are custom data entries controlled by your app. Your app manages both the structure and values, which are view only in the Shopify admin (by default).

App-ownership is defined using the app reserved namespace.

Info

App-owned data is viewable by default in the Shopify admin. If you need to store data that is not visible, consider App-data metafields.

You want to track internal SKU codes for products. Because your app manages inventory tracking, you create an app-owned metafield.

Anchor to Step 1: Create the metafield definitionStep 1: Create the metafield definition

Create the metafield definition using your app's shopify.app.toml file. The following creates the definition with app-owned namespace app and key internal_sku:

File

shopify.app.toml
[product.metafields.app.internal_sku]
name = "Internal SKU"
description = "Internal inventory tracking code"
type = "single_line_text_field"

Deploy it with your app:

Terminal

shopify app deploy

Anchor to Step 2: Create the metafieldStep 2: Create the metafield

After you create the metafield definition, add the metafield (value) using the GraphQL Admin API. Use the same namespace, key, and type from the definition:

GraphQL

POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
mutation AddInternalSKU {
productUpdate(
input: {
id: "gid://shopify/Product/123456789"
metafields: [
{
namespace: "$app"
key: "internal_sku"
value: "INV-2024-COTTON-001"
type: "single_line_text_field"
}
]
}
) {
product {
id
metafield(namespace: "$app", key: "internal_sku") {
id
value
}
}
userErrors {
field
message
}
}
}
Note

Get a product ID by querying products(first: 1) in GraphiQL, or find it in the Shopify admin URL when viewing a product: /admin/products/123456789.


Anchor to Merchant-owned metafieldsMerchant-owned metafields

Merchant-owned metafields are custom data entries that merchants and all installed apps can modify. Both the structure and values are editable, making them ideal for shared data across multiple apps.

Create merchant-owned metafields using any non-reserved namespace (such as custom, specs, or inventory).

Info

Merchant-owned definitions can't be created in shopify.app.toml.

You want to add warranty information to products. Because this type of field should be managed in the Shopify admin, you use a merchant-owned metafield.

Anchor to Step 1: Create the metafield definitionStep 1: Create the metafield definition

First, create the metafield definition using the GraphQL Admin API. The following example doesn't use namespace $app, so the definition will be merchant-owned:

GraphQL

POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
mutation {
metafieldDefinitionCreate(definition: {
name: "Warranty Information",
namespace: "custom",
key: "warranty_info",
description: "Product warranty details and coverage information",
type: "multi_line_text_field",
ownerType: PRODUCT,
access: {
storefront: PUBLIC_READ,
},
}) {
createdDefinition {
name
namespace
key
type
access
}
}
}

Anchor to Step 2: Create the metafieldStep 2: Create the metafield

After you create the metafield definition, add the metafield (value). Use the same namespace, key, and type from the definition:

GraphQL

POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
mutation AddWarrantyInfo {
productUpdate(
input: {
id: "gid://shopify/Product/123456789"
metafields: [
{
namespace: "custom"
key: "warranty_info"
value: "2-year manufacturer warranty. Covers defects in materials and workmanship."
type: "multi_line_text_field"
}
]
}
) {
product {
id
metafield(namespace: "custom", key: "warranty_info") {
id
value
}
}
userErrors {
field
message
}
}
}

App-data metafields are tied to a specific app installation and are completely hidden from the Shopify admin. They're stored on the AppInstallation resource and can only be accessed by the owning app via GraphQL or through the app object in Liquid. They can't be created using shopify.app.toml.

Unlike app-owned metafields on shared resources, the $app reserved namespace isn't required because the AppInstallation owner provides isolation — only your app can access its own installation's metafields.

Caution

Generally, private app data should be stored in an app-specific, secure database. App-data metafields can be used for per-installation configuration values, but sensitive credentials should be stored in environment variables or a dedicated secret management system.

You want to store a feature tier configuration for each app installation. Because this data should be completely hidden from merchants and specific to each installation, you use app-data metafields.

Anchor to Step 1: Retrieve the app installation IDStep 1: Retrieve the app installation ID

Get the app installation ID using the currentAppInstallation query:

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

GraphQL query

query {
currentAppInstallation {
id
}
}

Response

{
"data": {
"currentAppInstallation": {
"id": "gid://shopify/AppInstallation/123456"
}
}
}

Anchor to Step 2: Create the app-data metafieldStep 2: Create the app-data metafield

Create the app-data metafield using the metafieldsSet mutation:

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

GraphQL mutation

mutation CreateAppDataMetafield($metafieldsSetInput: [MetafieldsSetInput!]!) {
metafieldsSet(metafields: $metafieldsSetInput) {
metafields {
id
namespace
key
}
userErrors {
field
message
}
}
}

Variables

{
"metafieldsSetInput": [
{
"namespace": "app_config",
"key": "feature_tier",
"type": "single_line_text_field",
"value": "premium",
"ownerId": "gid://shopify/AppInstallation/123456"
}
]
}

Configure who can read and write your metafields using the access settings on your definition.

Anchor to Shopify admin permissionsShopify admin permissions

admin controls permissions for both the Shopify admin and the GraphQL Admin API.

For app-owned metafields:

# Merchants can view but not edit (default)
access.admin = "merchant_read"

# Merchants can view and edit
access.admin = "merchant_read_write"
access: {
admin: MERCHANT_READ # view only (default)
}

access: {
admin: MERCHANT_READ_WRITE # view and edit
}

For merchant-owned metafields:

  • Always full access - readable and writable by merchants and all apps with appropriate scopes. No configuration needed.

Anchor to Storefront permissionsStorefront permissions

storefront controls permissions for the Storefront API (used by headless and custom storefronts). This setting doesn't affect Liquid templates - metafields are always accessible in Liquid regardless of this setting.

Available settings:

# Hidden from Storefront API (default)
access.storefront = "none"

# Accessible in Storefront API
access.storefront = "public_read"
access: {
storefront: NONE # hidden (default)
}

access: {
storefront: PUBLIC_READ # accessible
}
Note

Metafield access depends on its owning resource.

Anchor to Customer accounts permissionsCustomer accounts permissions

customer_accounts controls permissions for the Customer Accounts API.

Available settings:

# Hidden from Customer Accounts API (default)
access.customer_account = "none"

# Readable in Customer Accounts API
access.customer_account = "read"

# Readable and writable in Customer Accounts API
access.customer_account = "read_write"
access: {
customerAccount: NONE # hidden (default)
}

access: {
customerAccount: READ # readable
}

access: {
customerAccount: READ_WRITE # readable and writable
}
Note

Customer Account API access levels can only be adjusted via GraphQL Admin API mutation for app-owned metafields (namespace app--). For merchant-owned metafields, Customer Account API access can only be configured through the Shopify admin.



Was this page helpful?