MeiliSearch
Open-source search engine for your storefront
MedusaJS v2 MeiliSearch Plugin with i18n Support
This plugin integrates MeiliSearch with your Medusa e-commerce store and adds support for internationalization (i18n) of your product catalog.
Features
- Full-text search for your Medusa store
- Real-time indexing
- Typo-tolerance
- Faceted search
- Support for both products and categories
- Internationalization (i18n) support with multiple strategies:
- Separate index per language
- Language-specific fields with suffix
- Flexible translation configuration
- Custom field transformations
- Automatic field detection
Installation
Run the following command to install the plugin with npm:
1npm install --save @rokmohar/medusa-plugin-meilisearch
Or with yarn:
1yarn add @rokmohar/medusa-plugin-meilisearch
Upgrade to v1.0
This step is required only if you are upgrading from previous version to v1.0.
- The plugin now supports new MedusaJS plugin system.
- Subscribers are included in the plugin.
- You don't need custom subscribers anymore, you can remove them.
⚠️ MedusaJS v2.4.0 or newer
This plugin is only for MedusaJS v2.4.0 or newer.
If you are using MedusaJS v2.3.1 or older, please use the older version of this plugin.
Configuration
Add the plugin to your Copy to clipboardmedusa-config.ts
file:
1234567891011121314151617181920import { loadEnv, defineConfig } from '@medusajs/framework/utils'import { MeilisearchPluginOptions } from '@rokmohar/medusa-plugin-meilisearch'loadEnv(process.env.NODE_ENV || 'development', process.cwd())module.exports = defineConfig({// ... other configplugins: [// ... other plugins{resolve: '@rokmohar/medusa-plugin-meilisearch',options: {config: {host: process.env.MEILISEARCH_HOST ?? '',apiKey: process.env.MEILISEARCH_API_KEY ?? '',},settings: {// The key is used as the index name in Meilisearchproducts: {// Required: Index type
⚠️ Worker Mode Considerations
Important: Product events and background tasks will not work if your Medusa instance is running in Copy to clipboardserver
mode, because the server instance does not process subscribers or background jobs.
Depending on your setup:
- Monolithic architecture (only one backend instance):
Ensure you do not set the Copy to clipboardMEDUSA_WORKER_MODE
or Copy to clipboardWORKER_MODE
environment variable. By default, Medusa will use Copy to clipboardshared
mode, which supports both background processing and serving HTTP requests from the same instance. - Split architecture (separate server and worker instances):
Follow the official Medusa documentation on worker mode.
In this case, you must add this plugin in the worker instance, as the server instance does not handle event subscribers or background tasks.
i18n Configuration
The plugin supports two main strategies for handling translations, with flexible configuration options for each.
Basic Configuration
123456789101112{i18n: {// Choose strategy: 'separate-index' or 'field-suffix'strategy: 'field-suffix',// List of supported languageslanguages: ['en', 'fr', 'de'],// Default language to fall back todefaultLanguage: 'en',// Optional: List of translatable fieldstranslatableFields: ['title', 'description', 'handle']}}
Advanced Field Configuration
You can provide detailed configuration for each translatable field:
1234567891011121314151617181920{i18n: {strategy: 'field-suffix',languages: ['en', 'fr', 'de'],defaultLanguage: 'en',translatableFields: [// Simple field name'title',// Field with different target name{source: 'description',target: 'content' // Will be indexed as content_en, content_fr, etc.},// Field with transformation{source: 'handle',transform: (value) => value.toLowerCase().replace(/\s+/g, '-')}
Custom Translation Transformer
The plugin provides a flexible way to transform your products with custom translations. Instead of relying on specific storage formats, you can provide translations directly to the transformer:
1234567891011121314151617181920import { transformProduct } from '@rokmohar/medusa-plugin-meilisearch'const getProductTranslations = async (productId: string) => {// Example: fetch from your translation service/databasereturn {title: [{ language_code: 'en', value: 'Blue T-Shirt' },{ language_code: 'fr', value: 'T-Shirt Bleu' },],description: [{ language_code: 'en', value: 'A comfortable blue t-shirt' },{ language_code: 'fr', value: 'Un t-shirt bleu confortable' },],}}// Example usage in your custom transformerconst customTransformer = async (product, options) => {const translations = await getProductTranslations(product.id)
Integration with Tolgee
For production environments, you'll often want to integrate with external translation management platforms. Here's an example of integrating with Tolgee, a popular translations management platform:
1234567891011121314151617181920import { default as axios } from 'axios'import { logger } from '@medusajs/framework'import { TranslationMap } from '@rokmohar/medusa-plugin-meilisearch'type TranslationsHttpResponse = {[lang: string]: {[id: string]: Record<string, string>}}const options = {apiKey: process.env.TOLGEE_API_KEY ?? '',baseURL: process.env.TOLGEE_API_URL ?? '',projectId: process.env.TOLGEE_PROJECT_ID ?? '',}const httpClient = axios.create({baseURL: `${options.baseURL}/v2/projects/${options.projectId}`,headers: {Accept: 'application/json',
Usage in your transformer configuration:
12345678910111213141516{settings: {products: {type: 'products',// ... other configtransformer: async (product, defaultTransformer, options) => {const translations = await getTranslations(product.id, ['sl', 'en'])return defaultTransformer(product, {...options,translations,includeAllTranslations: true})},}}}
This integration fetches translations from Tolgee's API and transforms them into the format expected by this plugin. For complete storefront translation management, consider using the medusa-plugin-tolgee by SteelRazor47, which provides comprehensive translation management features including admin widgets.
i18n Strategies
1. Separate Index per Language
This strategy creates a separate MeiliSearch index for each language. For example, if your base index is named "products", it will create:
- products_en
- products_fr
- products_de
Benefits:
- Better performance for language-specific searches
- Language-specific settings and ranking rules
- Cleaner index structure
2. Language-specific Fields with Suffix
This strategy adds language suffixes to translatable fields in the same index. For example:
- title_en, title_fr, title_de
- description_en, description_fr, description_de
Benefits:
- Single index to maintain
- Ability to search across all languages at once
- Smaller storage requirements
Custom Translatable Fields
If no translatable fields are specified and using the field-suffix strategy, the plugin will automatically detect string fields as translatable. You can override this by explicitly specifying the fields:
123456789{i18n: {strategy: 'field-suffix',languages: ['en', 'fr'],defaultLanguage: 'en',// Only these fields will be translatabletranslatableFields: ['title', 'description']}}
Product API Endpoints
Search for Product Hits
1GET /store/meilisearch/products-hits
Query Parameters:
- Copy to clipboard
query
: Search query string - Copy to clipboard
limit
: (Optional) Limit results from search - Copy to clipboard
offset
: (Optional) Offset results from search - Copy to clipboard
language
: (Optional) Language code - Copy to clipboard
semanticSearch
- Enable AI-powered semantic search (boolean) - Copy to clipboard
semanticRatio
- Semantic vs keyword search ratio (0-1)
Search for Products
1GET /store/meilisearch/products
Query Parameters:
- Copy to clipboard
fields
- MedusaJS fields expression - Copy to clipboard
limit
: (Optional) Limit results from search - Copy to clipboard
offset
: (Optional) Offset results from search - Copy to clipboard
region_id
: (Optional, but required for Copy to clipboardcalculated_price
) Current region ID - Copy to clipboard
currency_code
: (Optional, but required for Copy to clipboardcalculated_price
) Current currency code - Copy to clipboard
query
: Search query string - Copy to clipboard
language
: (Optional) Language code - Copy to clipboard
semanticSearch
- Enable AI-powered semantic search (boolean) - Copy to clipboard
semanticRatio
- Semantic vs keyword search ratio (0-1)
Category Support
This plugin provides full support for MedusaJS v2 categories, including:
- Real-time indexing of category changes
- i18n support for category names and descriptions
- Hierarchical category structure support with parent-child relationships
- Custom category field transformations
Category Configuration Example
1234567891011121314151617181920{settings: {categories: {type: 'categories',enabled: true,fields: ['id', 'name', 'description', 'handle', 'is_active', 'parent_id'],indexSettings: {searchableAttributes: ['name', 'description'],displayedAttributes: ['id', 'name', 'description', 'handle', 'is_active', 'parent_id'],filterableAttributes: ['id', 'handle', 'is_active', 'parent_id'],},primaryKey: 'id',},},i18n: {strategy: 'field-suffix',languages: ['en', 'fr', 'de'],defaultLanguage: 'en',translatableFields: ['name', 'description'], // Category-specific translatable fields},
Category API Endpoints
Search for Category Hits
1GET /store/meilisearch/categories-hits
Query Parameters:
- Copy to clipboard
query
: Search query string - Copy to clipboard
limit
: (Optional) Limit results from search - Copy to clipboard
offset
: (Optional) Offset results from search - Copy to clipboard
language
: (Optional) Language code - Copy to clipboard
semanticSearch
- Enable AI-powered semantic search (boolean) - Copy to clipboard
semanticRatio
- Semantic vs keyword search ratio (0-1)
Search for Categories
1GET /store/meilisearch/categories
Query Parameters:
- Copy to clipboard
fields
- MedusaJS fields expression - Copy to clipboard
limit
: (Optional) Limit results from search - Copy to clipboard
offset
: (Optional) Offset results from search - Copy to clipboard
query
: Search query string - Copy to clipboard
language
: (Optional) Language code - Copy to clipboard
semanticSearch
- Enable AI-powered semantic search (boolean) - Copy to clipboard
semanticRatio
- Semantic vs keyword search ratio (0-1)
AI-Powered Semantic Search
This plugin supports AI-powered semantic search using vector embeddings. See docs/semantic-search.md for detailed configuration and usage instructions.
ENV variables
Add the environment variables to your Copy to clipboard.env
and Copy to clipboard.env.template
file:
123# ... others varsMEILISEARCH_HOST=MEILISEARCH_API_KEY=
If you want to use with the Copy to clipboarddocker-compose
from this README, use the following values:
123# ... others varsMEILISEARCH_HOST=http://127.0.0.1:7700MEILISEARCH_API_KEY=ms
docker-compose
You can add the following configuration for Meilisearch to your Copy to clipboarddocker-compose.yml
:
12345678910111213141516services:# ... other servicesmeilisearch:image: getmeili/meilisearch:latestports:- '7700:7700'volumes:- ~/data.ms:/data.msenvironment:- MEILI_MASTER_KEY=mshealthcheck:test: ['CMD', 'curl', '-f', 'http://localhost:7700']interval: 10stimeout: 5sretries: 5
Add search to Medusa NextJS starter
You can find instructions on how to add search to a Medusa NextJS starter inside the nextjs folder.
FAQ
- How do I include product categories and tags in my search index?
- How do I include product variant prices (min_price, max_price) in my search index?
- How do I include prices in the search response from the search endpoint?
Contributing
Feel free to open issues and pull requests!