Skip to main content
When a facet attribute has thousands of unique values (for example, a brand attribute with 5,000 brands or a city attribute with 10,000 cities), displaying all values at once becomes impractical. Meilisearch provides tools to handle this efficiently.

Understand the challenge

By default, Meilisearch returns at most 100 facet values per attribute in the facetDistribution response. This limit is configurable through the maxValuesPerFacet setting:
curl \
  -X PATCH 'MEILISEARCH_URL/indexes/products/settings/faceting' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer MEILISEARCH_KEY' \
  --data-binary '{
    "maxValuesPerFacet": 200
  }'
Increasing maxValuesPerFacet returns more values but slows down search responses and increases payload size. For high-cardinality attributes, a better approach is to let users search within facet values.

Search within facet values

The facet search endpoint lets users type to find specific facet values. This is the primary tool for handling high-cardinality facets.
curl \
  -X POST 'MEILISEARCH_URL/indexes/products/facet-search' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer MEILISEARCH_KEY' \
  --data-binary '{
    "facetName": "brand",
    "facetQuery": "ni"
  }'
The response returns matching facet values with their document counts:
{
  "facetHits": [
    { "value": "Nike", "count": 342 },
    { "value": "Nikon", "count": 28 },
    { "value": "Nintendo", "count": 15 },
    { "value": "Ninja", "count": 7 }
  ],
  "facetQuery": "ni",
  "processingTimeMs": 1
}

Combine facet search with a query

Facet search results are context-aware. You can pass a q parameter to narrow facet values to those relevant to the user’s search:
curl \
  -X POST 'MEILISEARCH_URL/indexes/products/facet-search' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer MEILISEARCH_KEY' \
  --data-binary '{
    "facetName": "brand",
    "facetQuery": "ni",
    "q": "running shoes"
  }'
This returns only brands starting with “ni” that have running shoes. Without q, you might get “Nikon” and “Nintendo” which sell cameras and consoles, not shoes. You can also apply filters to further restrict facet search results:
curl \
  -X POST 'MEILISEARCH_URL/indexes/products/facet-search' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer MEILISEARCH_KEY' \
  --data-binary '{
    "facetName": "brand",
    "facetQuery": "ni",
    "q": "running shoes",
    "filter": "price < 200"
  }'

Build a searchable facet UI

For high-cardinality facets, replace the traditional checkbox list with a search input. The typical pattern is:
  1. Show the top 5-10 facet values from facetDistribution (most common values)
  2. Add a search input below the initial values
  3. When the user types, call the facet search endpoint
  4. Display matched facet values as selectable options
// Show top facet values from the main search response
const topBrands = searchResponse.facetDistribution.brand;

// When user types in the facet search input
async function searchBrands(query) {
  const response = await fetch(
    `${MEILISEARCH_URL}/indexes/products/facet-search`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${API_KEY}`
      },
      body: JSON.stringify({
        facetName: 'brand',
        facetQuery: query,
        q: currentSearchQuery // keep context with the main search
      })
    }
  );
  const data = await response.json();
  return data.facetHits; // [{ value: "Nike", count: 42 }, ...]
}

Performance considerations

High-cardinality facets affect indexing time and storage. Here are strategies to keep performance in check:

Keep maxValuesPerFacet reasonable

Avoid setting maxValuesPerFacet to very high values. Instead, rely on facet search for discovery. A value of 100 (the default) is sufficient for most UIs when combined with facet search.

Disable facet search for low-cardinality attributes

If some facets have few values (like color with 10 options) and others have many (like brand with 5,000), you only need facet search for the high-cardinality ones. You can disable facet search globally if no attribute needs it:
curl \
  -X PUT 'MEILISEARCH_URL/indexes/products/settings/facet-search' \
  -H 'Content-Type: application/json' \
  --data-binary 'false'
Disabling facet search reduces indexing time, as Meilisearch skips building the data structures needed for searching within facet values.

Sort facet values by count

For high-cardinality attributes, sorting by count (descending) ensures the most relevant values appear first:
curl \
  -X PATCH 'MEILISEARCH_URL/indexes/products/settings/faceting' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer MEILISEARCH_KEY' \
  --data-binary '{
    "sortFacetValuesBy": {
      "brand": "count"
    }
  }'
With this setting, facetDistribution returns brands ordered by how many matching documents each brand has, making the default view more useful.

Next steps

Search with facets

Learn the basics of faceted search

Build faceted navigation

Build a complete faceted search UI

Facet search API reference

Full API reference for the facet search endpoint