Aprende a añadir Meilisearch a tu backend para una búsqueda rápida y tolerante a errores tipográficos: configuración, indexación, ranking, filtros, seguridad y conceptos básicos de escalado.

La búsqueda del lado del servidor significa que la consulta se procesa en tu servidor (o en un servicio de búsqueda dedicado), no dentro del navegador. Tu app envía una petición de búsqueda, el servidor la ejecuta contra un índice y devuelve resultados ordenados.
Esto importa cuando tu conjunto de datos es demasiado grande para enviarlo al cliente, cuando necesitas relevancia consistente en varias plataformas o cuando el control de acceso es innegociable (por ejemplo, herramientas internas donde los usuarios solo deben ver lo que les está permitido). También es la elección por defecto cuando quieres analíticas, registro y rendimiento predecible.
La gente no piensa en motores de búsqueda: juzga la experiencia. Un buen flujo de búsqueda “instantánea” suele significar:
Si falta alguno de estos, los usuarios compensan probando distintas consultas, desplazándose más o abandonando la búsqueda por completo.
Este artículo es una guía práctica para construir esa experiencia con Meilisearch. Cubriremos cómo configurarlo de forma segura, cómo estructurar y sincronizar tus datos indexados, cómo ajustar la relevancia y las reglas de ranking, cómo añadir filtros/ordenación/facetas y cómo pensar en seguridad y escalado para que la búsqueda siga siendo rápida a medida que tu app crece.
Meilisearch encaja bien en:
El objetivo: resultados que se sientan inmediatos, precisos y confiables —sin convertir la búsqueda en un gran proyecto de ingeniería.
Meilisearch es un motor de búsqueda que ejecutas junto a tu app. Le envías documentos (como productos, artículos, usuarios o tickets de soporte) y construye un índice optimizado para búsquedas rápidas. Tu backend (o frontend) consulta Meilisearch mediante una API HTTP simple y recibe resultados ordenados en milisegundos.
Meilisearch se centra en las características que la gente espera de una búsqueda moderna:
Está diseñado para sentirse receptivo y tolerante, incluso cuando una consulta es corta, ligeramente incorrecta o ambigua.
Meilisearch no reemplaza tu base de datos principal. Tu base de datos sigue siendo la fuente de la verdad para escrituras, transacciones y restricciones. Meilisearch almacena una copia de los campos que elijas hacer buscables, filtrables o mostrables.
Un buen modelo mental es: base de datos para almacenar y actualizar, Meilisearch para encontrarlo rápidamente.
Meilisearch puede ser extremadamente rápido, pero los resultados dependen de algunos factores prácticos:
Para conjuntos pequeños o medianos, a menudo puedes ejecutarlo en una única máquina. A medida que tu índice crece, querrás ser más deliberado sobre qué indexas y cómo lo mantienes actualizado: temas que cubriremos más adelante.
Antes de instalar nada, decide qué vas a buscar realmente. Meilisearch se sentirá “instantáneo” solo si tus índices y documentos coinciden con la forma en que la gente navega tu app.
Empieza listando tus entidades buscables —típicamente productos, artículos, usuarios, documentos de ayuda, ubicaciones, etc. En muchas apps, el enfoque más limpio es un índice por tipo de entidad (por ejemplo, products, articles). Eso mantiene las reglas de ranking y los filtros previsibles.
Si tu UX busca a través de varios tipos en una sola caja (“buscar en todo”), aún puedes mantener índices separados y combinar resultados en tu backend, o crear un índice “global” dedicado más adelante. No forces todo en un solo índice a menos que los campos y filtros estén realmente alineados.
Cada documento necesita un identificador estable (clave primaria). Elige algo que:
id, sku, slug)Para la forma del documento, prefiere campos planos cuando puedas. Las estructuras planas son más fáciles de filtrar y ordenar. Los campos anidados están bien cuando representan un paquete pequeño e inmutable (por ejemplo, un objeto author), pero evita anidamientos profundos que reflejen todo tu esquema relacional: los documentos de búsqueda deben estar optimizados para lectura, no tener la forma de la base de datos.
Una forma práctica de diseñar documentos es etiquetar cada campo con un rol:
Esto evita un error común: indexar un campo “por si acaso” y luego preguntarse por qué los resultados son ruidosos o los filtros lentos.
“Idioma” puede significar cosas distintas en tus datos:
lang: "en")Decide pronto si usarás índices separados por idioma (simple y predecible) o un índice único con campos de idioma (menos índices, más lógica). La respuesta correcta depende de si los usuarios buscan en un idioma a la vez y cómo almacenas las traducciones.
Ejecutar Meilisearch es sencillo, pero “seguro por defecto” requiere algunas decisiones: dónde desplegarlo, cómo persistir datos y cómo manejar la clave maestra.
Almacenamiento: Meilisearch escribe su índice en disco. Coloca el directorio de datos en almacenamiento confiable y persistente (no en almacenamiento efímero de contenedores). Planifica capacidad para el crecimiento: los índices pueden expandirse rápidamente con campos de texto grandes y muchos atributos.
Memoria: asigna suficiente RAM para mantener la búsqueda responsiva bajo carga. Si hay swapping, el rendimiento empeorará.
Backups: haz copia de seguridad del directorio de datos de Meilisearch (o usa snapshots en la capa de almacenamiento). Prueba la restauración al menos una vez; una copia que no puedes restaurar es solo un archivo.
Monitorización: supervisa CPU, RAM, uso de disco y E/S de disco. También monitoriza la salud del proceso y los errores en logs. Como mínimo, alerta si el servicio se detiene o si el disco se queda sin espacio.
Siempre ejecuta Meilisearch con una master key en cualquier entorno que no sea de desarrollo local. Almacénala en un gestor de secretos o en un almacén de variables de entorno cifrado (no en Git, no en un .env en texto plano comprometido).
Ejemplo (Docker):
docker run -d --name meilisearch \
-p 7700:7700 \
-v meili_data:/meili_data \
-e MEILI_MASTER_KEY="$(openssl rand -hex 32)" \
getmeili/meilisearch:latest
También considera reglas de red: enlaza a una interfaz privada o restringe el acceso entrante para que solo tu backend pueda alcanzar Meilisearch.
curl -s http://localhost:7700/version
La indexación en Meilisearch es asíncrona: envías documentos, Meilisearch pone en cola una tarea y solo después de que esa tarea tenga éxito esos documentos se vuelven buscables. Trata la indexación como un sistema de trabajos, no como una sola petición.
id).curl -X POST 'http://localhost:7700/indexes/products/documents?primaryKey=id' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer YOUR_WRITE_KEY' \
--data-binary @products.json
taskUid. Haz polling hasta que sea succeeded (o failed).curl -X GET 'http://localhost:7700/tasks/123' \
-H 'Authorization: Bearer YOUR_WRITE_KEY'
curl -X GET 'http://localhost:7700/indexes/products/stats' \
-H 'Authorization: Bearer YOUR_WRITE_KEY'
Si los conteos no coinciden, no adivines: revisa primero los detalles de error de la tarea.
El batching consiste en mantener las tareas predecibles y recuperables.
addDocuments funciona como un upsert: los documentos con la misma clave primaria se actualizan, los nuevos se insertan. Úsalo para actualizaciones normales.
Haz una reindexación completa cuando:
Para eliminaciones, llama explícitamente a deleteDocument(s); de lo contrario los registros antiguos pueden permanecer.
La indexación debe ser reintentable. La clave es IDs de documento estables.
taskUid devuelto junto con el id de tu lote/trabajo y reintenta según el estado de la tarea.Antes de datos de producción, indexa un pequeño conjunto (200–500 ítems) que coincida con tus campos reales. Ejemplo: un conjunto de products con id, name, description, category, brand, price, inStock, createdAt. Esto es suficiente para validar el flujo de tareas, conteos y comportamiento de update/delete —sin esperar una importación masiva.
La “relevancia” de búsqueda es simplemente: qué aparece primero y por qué. Meilisearch hace esto ajustable sin obligarte a construir tu propio sistema de puntuación.
Dos ajustes determinan lo que Meilisearch puede hacer con tu contenido:
searchableAttributes: los campos en los que Meilisearch busca cuando un usuario escribe una consulta (por ejemplo: title, summary, tags). El orden importa: los campos anteriores se tratan como más importantes.displayedAttributes: los campos devueltos en la respuesta. Esto afecta la privacidad y el tamaño del payload: si un campo no está en displayed, no se enviará.Una línea base práctica es hacer buscables unos pocos campos de alta señal (title, texto clave) y mantener los displayed a lo que la UI necesita.
Meilisearch ordena documentos coincidentes usando ranking rules —una tubería de “desempates”. Conceptualmente, prefiere:
No necesitas memorizar los detalles internos para ajustarlo: principalmente eliges qué campos importan más y cuándo aplicar ordenación personalizada.
Objetivo: “Coincidencias en el título deben ganar.” Pon title primero:
{
"searchableAttributes": ["title", "subtitle", "description", "tags"]
}
Objetivo: “El contenido más nuevo debe aparecer primero.” Añade un atributo ordenable y ordena en tiempo de consulta (o establece un ranking personalizado):
{
"sortableAttributes": ["publishedAt"],
"rankingRules": ["sort", "typo", "words", "proximity", "attribute", "exactness"]
}
Luego solicita:
{ "q": "release notes", "sort": ["publishedAt:desc"] }
Objetivo: “Promover ítems populares.” Haz popularity ordenable y ordena por él cuando sea apropiado.
Elige 5–10 consultas reales que usen los usuarios. Guarda los resultados principales antes de los cambios y compáralos después.
Ejemplo:
"apple" → Apple Watch band, Pineapple slicer, Apple iPhone case"apple" → Apple iPhone case, Apple Watch band, Pineapple slicerSi la lista “después” se ajusta mejor a la intención del usuario, conserva la configuración. Si perjudica casos límite, ajusta una cosa a la vez (orden de atributos, luego reglas de orden) para saber qué causó la mejora.
Un buen cuadro de búsqueda no es solo “escribe palabras, obtén coincidencias”. La gente también quiere acotar resultados (“solo artículos disponibles”) y ordenarlos (“más barato primero”). En Meilisearch, haces esto con filtros, ordenación y facetas.
Un filtro es una regla que aplicas al conjunto de resultados. Una faceta es lo que muestras en la UI para ayudar a los usuarios a construir esas reglas (a menudo como checkboxes o conteos).
Ejemplos no técnicos:
Así un usuario puede buscar “running” y luego filtrar category = Shoes y status = in_stock. Las facetas pueden mostrar conteos como “Shoes (128)” y “Jackets (42)” para que los usuarios entiendan lo disponible.
Meilisearch necesita que explícitamente permitas los campos usados para filtrar y ordenar.
category, status, brand, price, created_at (si filtras por tiempo), tenant_id (si aíslas clientes).price, rating, created_at, popularity.Mantén esta lista ajustada. Hacer todo filtrable/ordenable puede aumentar el tamaño del índice y ralentizar las actualizaciones.
Aunque tengas 50.000 coincidencias, los usuarios solo ven la primera página. Usa páginas pequeñas (a menudo 20–50 resultados), establece un limit sensato y pagina con offset (o las funciones de paginación más nuevas si las prefieres). También limita la profundidad máxima de página en tu app para evitar costosas peticiones “página 400”.
Una forma limpia de añadir búsqueda del lado del servidor es tratar Meilisearch como un servicio de datos especializado detrás de tu API. Tu app recibe una petición de búsqueda, llama a Meilisearch y luego devuelve una respuesta curada al cliente.
La mayoría de equipos termina con un flujo como este:
GET /api/search?q=wireless+headphones&limit=20).Este patrón mantiene Meilisearch intercambiable y evita que el frontend dependa de internos del índice.
Si estás construyendo una app nueva (o reconstruyendo una herramienta interna) y quieres este patrón implementado rápido, una plataforma de vibe-coding como Koder.ai puede ayudar a generar el flujo completo —UI en React, backend en Go y PostgreSQL— e integrar Meilisearch detrás de un único endpoint /api/search para que el cliente se mantenga simple y los permisos queden en el servidor.
Meilisearch soporta consultas desde el cliente, pero consultar desde el backend suele ser más seguro porque:
La consulta desde frontend aún puede funcionar para datos públicos con claves restringidas, pero si tienes reglas de visibilidad por usuario, enruta la búsqueda a través de tu servidor.
El tráfico de búsqueda suele tener repeticiones (“iphone case”, “return policy”). Añade caché en la capa de tu API:
Trata la búsqueda como un endpoint público:
limit máximo y longitud máxima de consulta.Meilisearch a menudo se coloca “detrás” de tu app porque puede devolver datos sensibles de negocio rápidamente. Trátalo como una base de datos: ponle candado y expón solo lo que cada llamador debería ver.
Meilisearch tiene una master key que puede hacer todo: crear/eliminar índices, actualizar settings y leer/escribir documentos. Mantenla solo en servidor.
Para aplicaciones, genera claves API con acciones limitadas y límites de índice. Un patrón común:
El principio de menor privilegio significa que una clave filtrada no podrá borrar datos ni leer índices no relacionados.
Si sirves a múltiples clientes (tenants), tienes dos opciones principales:
1) Un índice por tenant.
Simple de razonar y reduce el riesgo de acceso cruzado entre tenants. Inconvenientes: más índices que gestionar y las actualizaciones de settings deben aplicarse de forma consistente.
2) Índice compartido + filtro por tenant.
Almacena un campo tenantId en cada documento y exige un filtro como tenantId = "t_123" en todas las búsquedas. Esto puede escalar bien, pero solo si aseguras que cada petición siempre aplique el filtro (idealmente mediante una clave con alcance para que los llamadores no puedan quitarlo).
Aunque la búsqueda sea correcta, los resultados pueden filtrar campos que no querías mostrar (emails, notas internas, precios de coste). Configura qué se puede devolver:
Haz una prueba rápida de “peor caso”: busca un término común y confirma que no aparecen campos privados.
Si dudas si una clave debe estar en cliente, asume “no” y mantén la búsqueda en el servidor.
Meilisearch es rápido cuando mantienes en mente dos cargas de trabajo: indexación (escrituras) y consultas de búsqueda (lecturas). La mayoría de la “lentitud misteriosa” es que una de estas compite por CPU, RAM o disco.
Carga de indexación puede subir cuando importas lotes grandes, ejecutas actualizaciones frecuentes o añades muchos campos buscables. La indexación es tarea en segundo plano, pero aún consume CPU y ancho de banda de disco. Si tu cola de tareas crece, las búsquedas pueden empezar a sentirse más lentas aunque el volumen de consultas no haya cambiado.
Carga de consultas crece con el tráfico, pero también con las características: más filtros, más facetas, conjuntos de resultados más grandes y más tolerancia a errores aumentan el trabajo por petición.
E/S de disco es el culpable silencioso. Discos lentos (o vecinos ruidosos en volúmenes compartidos) pueden convertir “instantáneo” en “eventual”. NVMe/SSD es la línea base típica para producción.
Empieza con un dimensionamiento simple: da a Meilisearch suficiente RAM para mantener índices calientes y suficiente CPU para manejar QPS pico. Luego separa preocupaciones:
Sigue un pequeño conjunto de señales:
Los backups deben ser rutinarios, no heroicos. Usa la función de snapshot de Meilisearch en un programa, guarda snapshots fuera del host y prueba restauraciones periódicamente. Para upgrades, lee las notas de la versión, prueba la actualización en un entorno no productivo y planifica el tiempo de reindexación si un cambio de versión afecta el comportamiento de indexación.
Si ya usas snapshots de entorno y rollback en tu plataforma (por ejemplo, mediante flujos de snapshots/rollback de Koder.ai), alinea tu despliegue de búsqueda con la misma disciplina: snapshot antes de cambios, verifica health checks y mantén una vía rápida de regreso a un estado conocido bueno.
Incluso con una integración limpia, los problemas de búsqueda suelen caer en unos cuantos bloques repetibles. La buena noticia: Meilisearch te da suficiente visibilidad (tareas, logs, settings deterministas) para depurar rápido —si lo abordas sistemáticamente.
filterableAttributes, o los documentos lo almacenan en una forma inesperada (string vs array vs objeto anidado).sortableAttributes/ajuste de rankingRules empujan los ítems “equivocados”.Empieza comprobando si Meilisearch aplicó con éxito tu último cambio.
filter, luego sort, luego facets.Si no puedes explicar un resultado, reduce temporalmente tu configuración: quita sinónimos, reduce ajustes de ranking y prueba con un dataset pequeño. Los problemas complejos de relevancia son mucho más fáciles de detectar en 50 documentos que en 5 millones.
your_index_v2 en paralelo, aplica settings y reproduce una muestra de consultas de producción.filterableAttributes y sortableAttributes coincidan con los requisitos de tu UI.Related guides: /blog (consejos sobre fiabilidad de búsqueda, patrones de indexación y despliegues en producción).
La búsqueda del lado del servidor significa que la consulta se ejecuta en tu backend (o en un servicio de búsqueda dedicado), no en el navegador. Es la opción correcta cuando:
Los usuarios notan cuatro cosas de inmediato:
Si falta uno, la gente reescribe consultas, desplaza demasiado o abandona la búsqueda.
Trátalo como un índice de búsqueda, no como tu fuente de la verdad. Tu base de datos maneja escrituras, transacciones y restricciones; Meilisearch almacena una copia de los campos seleccionados optimizados para la recuperación.
Un modelo mental útil:
Por defecto se suele usar un índice por tipo de entidad (por ejemplo, products, articles). Esto mantiene:
Si necesitas “buscar en todo”, puedes consultar varios índices y combinar resultados en tu backend, o añadir más adelante un índice global dedicado.
Elige una clave primaria que sea:
id, sku, slug)Los IDs estables hacen que la indexación sea idempotente: si reintentas una subida, no crearás duplicados porque las actualizaciones funcionan como upserts.
Clasifica cada campo por su propósito para no sobreindexar:
Mantener estos roles explícitos reduce resultados ruidosos y evita índices lentos o inflados.
La indexación es asíncrona: las subidas de documentos crean una tarea y los documentos son buscables solo después de que la tarea haya tenido éxito.
Un flujo fiable:
succeeded o failedSi los resultados parecen antiguos, revisa el estado de la tarea antes de investigar otra cosa.
Usa muchos lotes más pequeños en lugar de una única subida enorme. Puntos de partida prácticos:
Los lotes pequeños son más fáciles de reintentar, más sencillos de depurar (encontrar registros defectuosos) y tienen menos probabilidad de agotar tiempo de espera.
Dos palancas de alto impacto son:
searchableAttributes: qué campos se buscan y en qué orden de prioridadpublishedAt, price o popularityEnfoque práctico: toma 5–10 consultas reales, guarda los resultados superiores “antes”, cambia una configuración y compara el “después”.
La mayoría de los problemas con filtros/ordenación vienen de configuración faltante:
filterableAttributes para filtrar por élsortableAttributes para ordenarloTambién verifica la forma y el tipo del campo en los documentos (string vs array vs objeto anidado). Si un filtro falla, inspecciona el último estado de la tarea/configuración y confirma que los documentos indexados contienen los valores esperados.