Introducing custom attributes in Medusa.js (Part 1)

Viktor Holik
Rigby News
Published in
3 min readNov 3, 2023

The challenge

In our journey to create custom stores using Medusa.js in Rigby, we encountered a challenge with adding custom attributes to our products. Medusa.js lacked a built-in custom attribute API, so we had to resort to using 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-plugin-custom-attributes
// OR
yarn add medusa-plugin-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.

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 multiple attribute values from options
  3. Boolean
  4. Range — Integer
Testing a style attribute

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.

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 search parameter:

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

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

Conclusion

In conclusion, this plugin simplifies the management of custom attributes in Medusa.js, providing a more efficient way to add, filter, and display attributes. Check out the documentation and support the project on its GitHub repository.

--

--