Adding Custom Attributes in Medusa.js

By Viktor Holik

Featured image
custom attributes

The challenge

In our journey to create custom stores using Medusa.js in Rigby, we encountered a challenge with adding custom attributes to the products.

Medusa.js lacked a built-in custom attribute API, so we used the metadata field with key-value pairs to store our attributes. However, filtering these attributes proved to be a complex task, as they could be of various types, such as arrays, strings, or numbers. We turned to PostgreSQL JSONB queries, but this approach came with its own set of issues.

query.andWhere(
 `product.metadata->’attributes’->>’designer’ IN (:…designers)`,
 {
   designers,
 }
 );

Challenges with this approach included:

  1. Having to extend the query for each new attribute.
  2. Handling attributes that depend on product categories.
  3. Dealing with slow JSONB queries.

Solution

To address these limitations, we developed a new plugin, “medusa-custom-attributes”, which adds a custom attributes API to Medusa.js. Here’s how you can use it:

Install plugin:

npm install medusa-custom-attributes
// OR
yarn add medusa-custom-attributes

If you use product categories, enable them in your .env file:

MEDUSA_FF_PRODUCT_CATEGORIES=true

Next, add the plugin to your medusa-config.js file as follows:

const plugins = [
  // ...
  {
    resolve: `medusa-custom-attributes`,
    options: {
      enableUI: true,
      projectConfig: {
        store_cors: STORE_CORS,
        admin_cors: ADMIN_CORS,
      },
    },
  },
]

And run migrations:

npx medusa migrations run

After successfully adding the plugin, you can access the “Custom attributes” option in your admin panel.

custom attributes

Click add attribute

medusa-custom-attributes has 3 types of attributes:

  1. Single — Allows you to define 1 attribute value from options.
  2. Multiple — Allows you to define up to 5 attribute values from options (defining multiple count is configurable).
  3. Boolean
custom attributes 3

After adding an attribute and selecting categories (or leaving the categories field empty for a global attribute), you can select them in the product details page under the “Attributes” widget.

custom attributes 4

Using on the storefront

You can list attributes by accessing the /store/attributes route. In the response, attributes with the "filterable" field set to true are filterable. You can also filter attributes by categories using query parameters, like this:

/store/attributes?categories[0]=t-shirts

You’ll receive a response with attribute details and their values.

[
    {
        "id": "attr_01HE7NV34RT5E9HKGNQG0DJ551",
        "created_at": "2023-11-02T09:29:14.642Z",
        "updated_at": "2023-11-02T09:29:14.642Z",
        "name": "Style",
        "description": "Style attribute",
        "type": "multi",
        "handle": "style",
        "filterable": true,
        "metadata": null,
        "values": [
            {
                "id": "attr_val_01HE7NV34S6A6MR9ENT7RZF66Q",
                "created_at": "2023-11-02T09:29:14.642Z",
                "updated_at": "2023-11-02T09:29:14.642Z",
                "value": "Vintage",
                "metadata": null,
                "rank": 0
            },
            {
                "id": "attr_val_01HE7NV34SKH8NBQFCMM48KMDW",
                "created_at": "2023-11-02T09:29:14.642Z",
                "updated_at": "2023-11-02T09:29:14.642Z",
                "value": "Casual",
                "metadata": null,
                "rank": 1
            },
            {
                "id": "attr_val_01HE7NV34SZMADRN0S70M4ECA7",
                "created_at": "2023-11-02T09:29:14.642Z",
                "updated_at": "2023-11-02T09:29:14.642Z",
                "value": "Streetwear",
                "metadata": null,
                "rank": 2
            },
            {
                "id": "attr_val_01HE7NV34SZ95MCNYZPTTQVSF3",
                "created_at": "2023-11-02T09:29:14.642Z",
                "updated_at": "2023-11-02T09:29:14.642Z",
                "value": "Formal",
                "metadata": null,
                "rank": 3
            }
        ],
        "categories": [
            {
                "id": "pcat_pants",
                "created_at": "2023-10-22T17:43:13.981Z",
                "updated_at": "2023-10-22T17:43:13.981Z",
                "name": "Pants",
                "description": "",
                "handle": "pants",
                "is_active": true,
                "is_internal": false,
                "parent_category_id": null,
                "rank": 0
            }
        ]
    }
]

To filter products based on attributes, use the attributes_id search parameter:

/store/products?attributes[style][]=attr_val_01HE7NV34S6A6MR9ENT7RZF66Q&attributes[style][]=attr_val_01HE7NV34SKH8NBQFCMM48KMDW

Additionally, product store routes will include attribute_values, which you can use to display attributes in your product listings.

Conclusion

This plugin simplifies the management of custom attributes in Medusa.js, providing a more efficient way to add, filter, and display attributes. You can download the plugin here!

Other blog posts

Maintance Mode in Next.js Applications

But how to implement maintenance mode in Next.js? Is it as easy as configuring a plugin on WordPress for a few minutes? Of course it is!

Medusa vs Magento: Total cost of ownership

Magento, compared to Medusa, may lead to higher long-term costs due to its licensing model and the risk associated with the gradual decline in the popularity of the PHP language...

Tell us about your project

Got a project in mind? Let's make it happen!

By clicking “Send Message” you grant us, i.e., Rigby, consent for email marketing of our services as part of the communication regarding your project. You may withdraw your consent, for example via hello@rigbyjs.com.
More information
placeholder

Grzegorz Tomaka

Co-CEO & Co-founder

LinkedIn icon
placeholder

Jakub Zbaski

Co-CEO & Co-founder

LinkedIn icon