docs/developer/core-concepts/metafields.mdx
Metafields provide a flexible, type-safe system for adding custom structured data to Spree resources. Unlike metadata which is simple JSON storage, metafields are schema-defined with strong typing, validation, and visibility controls.
Use metafields for:
erDiagram
MetafieldDefinition ||--o{ Metafield : "defines schema for"
Product ||--o{ Metafield : "has many"
Variant ||--o{ Metafield : "has many"
Order ||--o{ Metafield : "has many"
MetafieldDefinition {
string namespace
string key
string name
string metafield_type
string resource_type
string display_on
}
Metafield {
string type
text value
string resource_type
}
flowchart LR
subgraph Definition
A[MetafieldDefinition] --> B["namespace: properties"]
A --> C["key: manufacturer"]
A --> D["type: ShortText"]
A --> E["resource_type: Product"]
A --> F["display_on: both"]
end
subgraph Instance
G[Metafield] --> H["value: Wilson"]
G --> I["resource: Product #1"]
end
A -.->|"defines schema"| G
| Type | Description | Example Values |
|---|---|---|
| Short Text | Brief text fields | SKU codes, brand names, tags |
| Long Text | Longer text content | Care instructions, notes |
| Rich Text | Formatted HTML content | Product descriptions with formatting |
| Number | Numeric values | Weight, quantity, ratings |
| Boolean | True/false flags | Is featured, requires signature |
| JSON | Structured data | Configuration, complex objects |
Metafields support three visibility levels via the display_on attribute:
| Visibility | Store API | Admin API | Use Case |
|---|---|---|---|
both | Yes | Yes | Public product specifications |
front_end | Yes | No | Customer-facing data |
back_end | No | Yes | Internal notes, integration IDs |
Metafields can be attached to most Spree resources including Products, Variants, Orders, Line Items, Taxons, Payments, Shipments, Gift Cards, Store Credits, and more.
<Info> Custom resources can also support metafields. See the [Customization Quickstart](/developer/customization/quickstart) for details. </Info>Namespaces organize metafields into logical groups and prevent key conflicts:
| Namespace | Example Keys | Purpose |
|---|---|---|
properties | manufacturer, material, fit | Product specifications |
shopify | product_id, variant_id | Integration data |
flags | featured, requires_approval | Feature flags |
custom | gift_message, delivery_notes | Business-specific fields |
Metafields with display_on set to both or front_end are included in Store API responses when you request the custom_fields expand:
const product = await client.products.get('spree-tote', {
expand: ['custom_fields'],
})
product.custom_fields?.forEach(field => {
console.log(field.key) // "properties.manufacturer"
console.log(field.label) // "Manufacturer"
console.log(field.value) // "Wilson"
console.log(field.type) // "short_text"
})
curl 'https://api.mystore.com/api/v3/store/products/spree-tote?expand=custom_fields' \
-H 'X-Spree-Api-Key: pk_xxx'
Response:
{
"id": "prod_86Rf07xd4z",
"name": "Spree T-Shirt",
"custom_fields": [
{
"id": "cf_k5nR8xLq",
"label": "Manufacturer",
"key": "properties.manufacturer",
"type": "short_text",
"value": "Wilson"
},
{
"id": "cf_m3Rp9wXz",
"label": "Material",
"key": "properties.material",
"type": "short_text",
"value": "100% Cotton"
}
]
}
Navigate to Settings → Metafield Definitions in the Admin Panel to create and manage metafield definitions. Select the resource type, enter namespace and key, choose the data type, and set visibility.
When editing a resource (e.g., a product), metafields appear in a dedicated section. The admin panel automatically builds forms for all defined metafields.
Spree has two permanent, complementary systems for custom data — metadata for machines, metafields for humans. They serve different purposes and are not interchangeable. Neither is going away.
| Feature | Metafields | Metadata |
|---|---|---|
| Purpose | Merchant-defined structured attributes | Developer escape hatch — integration IDs, sync state |
| Schema | Defined via MetafieldDefinitions | Schemaless JSON — no definition required |
| Validation | Type-specific (text, number, boolean, etc.) | None — accepts any JSON-serializable data |
| Visibility | Configurable (admin-only or public) | Write-only in Store API, readable in Admin API |
| Admin UI | Dedicated management forms | JSON preview |
| Data Types | 6 specific types | Any JSON value |
| Organization | Namespaced (namespace.key) | Flat key-value structure |
| Queryable | Via SQL joins, Ransack scopes, search providers | Via JSONB operators (PostgreSQL) |
Use Metafields when you need type validation, visibility control, admin UI forms, or organized namespacing.
Use Metadata for external system IDs, tracking attribution, syncing with integrations, or simple write-and-forget data that only backend systems need to read.
<Warning> Product Properties are deprecated and will be removed in Spree 6.0. For new projects, always use Metafields. For existing projects, plan to migrate using the [migration guide](/developer/upgrades/5.1-to-5.2#3-migrate-to-metafields-or-keep-using-properties). </Warning>