Skip to main content

Attribute Module

In this section of the documentation, you will find resources to learn more about the Attribute Module and how to use it in your application. Mercur has product attribute related features available out-of-the-box through the Attribute Module. A module is a standalone package that provides features for a single domain. Each of Mercur’s marketplace features are placed in custom modules, such as this Attribute Module. Learn more about why modules are isolated in this documentation.

Attribute Features

  • Attribute Management: Create and manage custom product attributes (e.g., Material, Size, Color, Condition) that can be applied to products.
  • Flexible Attribute Values: Store actual values assigned to products and manage predefined possible values for dropdown/select attributes.
  • Category-Specific Attributes: Associate attributes with product categories to define which attributes are applicable for products in each category.
  • Multiple UI Components: Support for different attribute input types including select, multivalue, unit, toggle, textarea, and color picker.
  • Product Organization: Link products to attribute values for enhanced filtering and search capabilities.

How to Use the Attribute Module

In your Medusa application, you build flows around Commerce Modules. A flow is built as a Workflow, which is a special function composed of a series of steps that guarantees data consistency and reliable roll-back mechanism. You can build custom workflows and steps. Mercur provides pre-built workflows for common attribute operations in the @mercurjs/b2c-core package. For example, the createAttributesWorkflow:
src/workflows/attribute/create-attributes.ts
import { LinkDefinition } from "@medusajs/framework/types"
import { Modules } from "@medusajs/framework/utils"
import {
  WorkflowData,
  WorkflowResponse,
  createWorkflow,
  transform,
  when,
} from "@medusajs/framework/workflows-sdk"
import { createRemoteLinkStep } from "@medusajs/medusa/core-flows"
import { CreateAttributeDTO } from "@mercurjs/framework"
import { createAttributesStep } from "../steps/create-attributes"

export const createAttributesWorkflow = createWorkflow(
  "create-attributes",
  (input: WorkflowData<{ attributes: CreateAttributeDTO[] }>) => {
    const attributesWithoutExternalRelations = transform(
      input,
      ({ attributes }) => {
        return attributes.map((attribute) => {
          delete attribute.product_category_ids
          return attribute
        })
      }
    )

    const createdAttributes = createAttributesStep(
      attributesWithoutExternalRelations
    )

    const productCategoryLinks: LinkDefinition[] = transform(
      { input, createdAttributes },
      ({ input, createdAttributes }) => {
        return createdAttributes
          .map((attribute, idx) => {
            const inputAttribute = input.attributes[idx]
            return (
              inputAttribute.product_category_ids?.map((productCategoryId) => ({
                [Modules.PRODUCT]: {
                  product_category_id: productCategoryId,
                },
                attribute: {
                  attribute_id: attribute.id,
                },
              })) || []
            )
          })
          .flat()
      }
    )

    when({ productCategoryLinks }, ({ productCategoryLinks }) => {
      return productCategoryLinks.length > 0
    }).then(() => {
      createRemoteLinkStep(productCategoryLinks)
    })

    return new WorkflowResponse(createdAttributes)
  }
)
You can then execute the workflow in your custom API routes:

API Route

src/api/admin/attributes/route.ts
import { MedusaRequest, MedusaResponse } from '@medusajs/framework'
import { ContainerRegistrationKeys } from '@medusajs/framework/utils'
import { createAttributesWorkflow } from '../../../workflows/attribute/workflows'

export const POST = async (
  req: MedusaRequest,
  res: MedusaResponse
) => {
  const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
  
  // Execute the createAttributesWorkflow
  const { result } = await createAttributesWorkflow(req.scope).run({
    input: { attributes: [req.validatedBody] }
  })

  const {
    data: [attribute]
  } = await query.graph({
    entity: 'attribute',
    filters: {
      id: result[0].id
    },
    ...req.queryConfig
  })

  res.status(201).json({ attribute })
}
Learn more about workflows in this documentation.

Concepts

In this document, you’ll learn about the main concepts related to attributes in Mercur.

Attribute

An attribute is a custom property that can be applied to products to provide additional product information and enable better filtering. It is represented by the Attribute data model. An attribute holds information about:
  • The name and description of the attribute (e.g., “Material”, “Size”)
  • A unique handle for programmatic access
  • Whether it’s required or filterable
  • The UI component type for rendering (select, multivalue, unit, toggle, textarea, color_picker)
  • Predefined possible values
  • Actual values assigned to products
Attributes can be associated with product categories to define which attributes are applicable for products in that category. For example, an “Electronics” category might have “Battery Life” and “Screen Size” attributes, while a “Clothing” category might have “Material” and “Size” attributes.

Attribute Value

An attribute value, represented by the AttributeValue data model, is the actual value assigned to a specific product for a given attribute. For example, if you have a “Material” attribute, one product might have an attribute value of “Cotton” while another has “Silk”. These are the actual values stored per product, not the predefined list. A product can have multiple attribute values, one for each attribute that applies to it.

Attribute Possible Value

An attribute possible value, represented by the AttributePossibleValue data model, defines the predefined list of allowed values for an attribute. This is particularly useful for attributes rendered as dropdowns or select inputs, where you want to provide a curated list of options to choose from. For example, for a “Material” attribute, you might define possible values of:
  • Cotton (rank: 1)
  • Polyester (rank: 2)
  • Silk (rank: 3)
The rank property determines the display order of these options in the UI.

UI Component Types

Each attribute can specify a UI component type that determines how it should be rendered in the admin panel or storefront:
  • select: Standard dropdown with single selection from predefined possible values
  • multivalue: Multiple selection from predefined possible values
  • unit: Numeric value with a unit of measurement (e.g., “10 kg”, “15 cm”)
  • toggle: Boolean on/off switch
  • text_area: Multi-line text input for longer descriptions
  • color_picker: Color selection interface for color attributes
This flexibility allows marketplace administrators to create appropriate input experiences for different types of product information.

Filterable Attributes

The is_filterable property on an attribute determines whether it should be used in product filtering and faceted search. When enabled, the attribute values can be used to:
  • Filter products in the storefront (e.g., “Show only Cotton products”)
  • Create faceted navigation (e.g., “Material: Cotton (23 products)”)
  • Power search engine filters (e.g., Algolia facets)
This is essential for creating rich product discovery experiences in the marketplace.

Required Attributes

The is_required property on an attribute determines whether sellers must provide a value for this attribute when creating or editing products. This is useful for enforcing data quality in the marketplace. For example, you might make “Condition” a required attribute for a second-hand marketplace to ensure all products have this information.

Use Cases

1. Enhanced Product Filtering Create rich filtering experiences by defining attributes like Size, Color, Material, and Condition. 2. Category-Specific Properties Define different attributes for different product categories (e.g., “Battery Life” for electronics, “Fabric Type” for clothing). 3. Dynamic Product Forms Use the ui_component property to automatically generate appropriate input fields in seller dashboards. 4. Search Engine Integration Filterable attributes can be synced to search engines like Algolia for powerful faceted search. 5. Data Quality Enforcement Use required attributes to ensure sellers provide essential product information.