Saiba como adicionar o Meilisearch ao seu backend para buscas rápidas e tolerantes a erros de digitação: configuração, indexação, regras de ordenação, filtros, segurança e noções de escalabilidade.

Pesquisa server-side significa que a consulta é processada no seu servidor (ou em um serviço de busca dedicado), não no navegador. Seu app envia uma requisição de busca, o servidor a executa contra um índice e retorna resultados ordenados.
Isso importa quando seu conjunto de dados é grande demais para enviar ao cliente, quando você precisa de relevância consistente entre plataformas, ou quando controle de acesso é inegociável (por exemplo, ferramentas internas onde usuários só devem ver o que lhes é permitido). Também é a escolha padrão quando você quer analytics, logs e desempenho previsível.
Pessoas não pensam em mecanismos de busca — elas avaliam a experiência. Um fluxo de busca “instantâneo” geralmente significa:
Se algum desses estiver faltando, os usuários compensam tentando consultas diferentes, rolando mais, ou abandonando a busca completamente.
Este artigo é um passo a passo prático para construir essa experiência com o Meilisearch. Cobriremos como configurá-lo com segurança, como estruturar e sincronizar seus dados indexados, como ajustar relevância e regras de ordenação, como adicionar filtros/ordenação/facetas e como pensar sobre segurança e escalabilidade para que a busca continue rápida conforme seu app cresce.
Meilisearch é uma boa opção para:
O objetivo ao longo do texto: resultados que pareçam imediatos, precisos e confiáveis — sem transformar a busca em um grande projeto de engenharia.
Meilisearch é um motor de busca que você roda ao lado do seu app. Você envia documentos (como produtos, artigos, usuários ou tickets de suporte) e ele constrói um índice otimizado para buscas rápidas. Seu backend (ou frontend) consulta o Meilisearch por uma API HTTP simples e recebe resultados ordenados em milissegundos.
O Meilisearch foca nas funcionalidades esperadas de buscas modernas:
É projetado para ser responsivo e tolerante, mesmo quando a consulta é curta, ligeiramente errada ou ambígua.
Meilisearch não substitui seu banco de dados primário. Seu banco continua sendo a fonte de verdade para gravações, transações e restrições. O Meilisearch armazena uma cópia dos campos que você escolhe tornar pesquisáveis, filtráveis ou exibíveis.
Um bom modelo mental é: banco de dados para armazenar e atualizar dados, Meilisearch para encontrá-los rapidamente.
Meilisearch pode ser extremamente rápido, mas os resultados dependem de alguns fatores práticos:
Para conjuntos pequenos a médios, muitas vezes é possível rodar em uma única máquina. À medida que o índice cresce, você precisará ser mais criterioso sobre o que indexar e como manter os dados atualizados — tópicos que cobriremos mais adiante.
Antes de instalar qualquer coisa, decida o que você realmente vai pesquisar. O Meilisearch será “instantâneo” somente se seus índices e documentos refletirem como as pessoas navegam no seu app.
Comece listando suas entidades pesquisáveis — tipicamente produtos, artigos, usuários, docs de ajuda, locais, etc. Em muitos apps, a abordagem mais limpa é um índice por tipo de entidade (por exemplo, products, articles). Isso mantém regras de ordenação e filtros previsíveis.
Se sua UX faz busca entre vários tipos em uma caixa (“buscar tudo”), você ainda pode manter índices separados e mesclar resultados no backend, ou criar um índice “global” mais tarde. Não force tudo em um índice a menos que os campos e filtros realmente se alinhem.
Cada documento precisa de um identificador estável (chave primária). Escolha algo que:
id, sku, slug)Para o formato do documento, prefira campos planos quando possível. Estruturas planas são mais fáceis de filtrar e ordenar. Campos aninhados são aceitáveis quando representam um conjunto coeso e estável (por exemplo, um objeto author), mas evite aninhamentos profundos que reflitam todo o seu esquema relacional — documentos de busca devem ser otimizados para leitura, não em formato de banco.
Uma maneira prática de projetar documentos é marcar cada campo com um papel:
Isso evita um erro comum: indexar um campo “só por precaução” e depois se perguntar por que os resultados ficam ruidosos ou os filtros lentos.
“Idioma” pode significar coisas diferentes nos seus dados:
lang: "en")Decida cedo se vai usar índices separados por idioma (simples e previsível) ou um único índice com campos de idioma (menos índices, mais lógica). A resposta certa depende se os usuários buscam em um idioma por vez e de como você armazena traduções.
Rodar o Meilisearch é direto, mas “seguros por padrão” exige algumas escolhas: onde você o deploya, como persistir dados e como lidar com a master key.
Armazenamento: Meilisearch grava índices em disco. Coloque o diretório de dados em armazenamento confiável e persistente (não em storage efêmero de container). Planeje capacidade para crescimento: índices podem aumentar rapidamente com campos de texto grandes e muitos atributos.
Memória: aloque RAM suficiente para manter a busca responsiva sob carga. Se notar swapping, o desempenho irá degradar.
Backups: faça backup do diretório de dados do Meilisearch (ou use snapshots no nível de storage). Teste a restauração pelo menos uma vez; um backup que não pode ser restaurado é só um arquivo.
Monitoramento: monitore CPU, RAM, uso de disco e I/O de disco. Também monitore a saúde do processo e registre erros. No mínimo, alerte se o serviço cair ou o disco estiver ficando sem espaço.
Sempre rode o Meilisearch com uma master key em qualquer coisa além de desenvolvimento local. Armazene-a em um gerenciador de segredos ou em um cofre de variáveis de ambiente criptografadas (não no Git, não em um .env em texto puro no repositório).
Exemplo (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
Considere também regras de rede: vincule a uma interface privada ou restrinja o acesso de entrada para que somente seu backend possa alcançar o Meilisearch.
curl -s http://localhost:7700/version
O indexamento no Meilisearch é assíncrono: você envia documentos, o Meilisearch enfileira uma task e só após essa task ter sucesso é que os documentos ficam pesquisáveis. Trate o indexamento como um sistema de jobs, não como uma única requisição.
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. Faça polling até que esteja succeeded (ou 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'
Se as contagens não baterem, não faça suposições — verifique primeiro os detalhes de erro da task.
Batching é sobre manter tasks previsíveis e recuperáveis.
addDocuments funciona como um upsert: documentos com a mesma chave primária são atualizados, novos são inseridos. Use isso para atualizações normais.
Faça uma reindexação completa quando:
Para remoções, chame explicitamente deleteDocument(s); caso contrário registros antigos podem permanecer.
Indexação deve ser reenviável. O pilar é ids de documento estáveis.
taskUid retornado junto com o id do seu batch/job, e reenvie com base no status da task.Antes dos dados de produção, indexe um pequeno conjunto (200–500 itens) que reflita seus campos reais. Exemplo: um conjunto products com id, name, description, category, brand, price, inStock, createdAt. Isso é suficiente para validar o fluxo de tasks, contagens e comportamento de update/delete — sem esperar por uma importação massiva.
“Relevância” de busca é simplesmente: o que aparece primeiro e por quê. O Meilisearch torna isso ajustável sem que você precise construir seu próprio sistema de pontuação.
Duas configurações determinam o que o Meilisearch pode fazer com seu conteúdo:
searchableAttributes: os campos em que o Meilisearch procura quando um usuário digita uma consulta (por exemplo: title, summary, tags). A ordem importa: campos anteriores são tratados como mais importantes.displayedAttributes: os campos retornados na resposta. Isso importa para privacidade e tamanho do payload — se um campo não é exibido, ele não será enviado.Uma base prática é tornar pesquisáveis alguns campos de alto sinal (title, texto-chave) e manter os campos exibidos apenas ao que a UI precisa.
O Meilisearch ordena documentos correspondentes usando ranking rules — um pipeline de “desempates”. Conceitualmente, ele prefere:
Você não precisa memorizar os detalhes internos para ajustar efetivamente; você escolhe principalmente quais campos importam e quando aplicar ordenação customizada.
Objetivo: “Matches no título devem ganhar.” Coloque title primeiro:
{
"searchableAttributes": ["title", "subtitle", "description", "tags"]
}
Objetivo: “Conteúdo mais novo deve aparecer primeiro.” Adicione um atributo ordenável e ordene na query (ou configure um ranking customizado):
{
"sortableAttributes": ["publishedAt"],
"rankingRules": ["sort", "typo", "words", "proximity", "attribute", "exactness"]
}
Então solicite:
{ "q": "release notes", "sort": ["publishedAt:desc"] }
Objetivo: “Promover itens populares.” Torne popularity ordenável e ordene por ele quando apropriado.
Escolha 5–10 consultas reais dos usuários. Salve os resultados principais antes das alterações e compare depois.
Exemplo:
"apple" → Apple Watch band, Pineapple slicer, Apple iPhone case"apple" → Apple iPhone case, Apple Watch band, Pineapple slicerSe a lista “depois” refletir melhor a intenção do usuário, mantenha as configurações. Se prejudicar casos de borda, ajuste uma coisa por vez (ordem de atributos, depois regras de ordenação) para saber o que causou a mudança.
Uma boa caixa de busca não é só “digite palavras, obtenha correspondências.” Pessoas também querem estreitar resultados (“apenas itens disponíveis”) e ordená-los (“mais barato primeiro”). No Meilisearch, isso é feito com filters, sort e facets.
Um filtro é uma regra aplicada ao conjunto de resultados. Uma faceta é o que você mostra na UI para ajudar os usuários a construir essas regras (geralmente como checkboxes ou contagens).
Exemplos práticos:
Assim, um usuário pode buscar “running” e depois filtrar para category = Shoes e status = in_stock. Facetas podem mostrar contagens como “Shoes (128)” e “Jackets (42)” para que os usuários entendam o que há disponível.
O Meilisearch exige que você permita explicitamente campos usados para filtragem e ordenação.
category, status, brand, price, created_at (se filtrar por tempo), tenant_id (se isolar clientes).price, rating, created_at, popularity.Mantenha essa lista enxuta. Tornar tudo filtrável/ordenável pode aumentar o tamanho do índice e tornar atualizações mais lentas.
Mesmo que você tenha 50.000 resultados, os usuários veem apenas a primeira página. Use páginas pequenas (frequentemente 20–50 resultados), defina limit sensato e pagine com offset (ou recursos de paginação mais novos, se preferir). Também limite a profundidade máxima de página no app para evitar requisições caras como “página 400”.
Uma maneira limpa de adicionar busca server-side é tratar o Meilisearch como um serviço de dados especializado atrás da sua API. Seu app recebe uma requisição de busca, chama o Meilisearch e retorna uma resposta curada ao cliente.
A maioria das equipes acaba com um fluxo assim:
GET /api/search?q=wireless+headphones&limit=20).Esse padrão mantém o Meilisearch substituível e impede que o código frontend dependa de detalhes internos do índice.
Se você estiver construindo um app novo (ou reescrevendo uma ferramenta interna) e quiser esse padrão implementado rapidamente, uma plataforma de scaffolding como Koder.ai pode ajudar a gerar o fluxo completo — UI em React, backend em Go e PostgreSQL — e integrar o Meilisearch atrás de um único endpoint /api/search para que o cliente permaneça simples e suas permissões fiquem no servidor.
O Meilisearch suporta consultas no cliente, mas consultar via backend costuma ser mais seguro porque:
Consultas no frontend ainda funcionam para dados públicos com chaves restritas, mas se houver regras de visibilidade por usuário, encaminhe a busca via servidor.
Tráfego de busca costuma ter repetições (“iphone case”, “return policy”). Adicione cache na camada da API:
Trate a busca como um endpoint público:
limit máximo e tamanho máximo de query.Meilisearch frequentemente fica “atrás” do seu app porque pode retornar dados sensíveis rapidamente. Trate-o como um banco: proteja, e exponha somente o que cada chamador deve ver.
Meilisearch tem uma master key que pode tudo: criar/excluir índices, atualizar settings e ler/gravar documentos. Mantenha-a apenas no servidor.
Para aplicações, gere chaves de API com ações limitadas e índices limitados. Um padrão comum:
Princípio do menor privilégio significa que uma chave vazada não pode apagar dados ou ler índices não relacionados.
Se você atende múltiplos clientes (tenants), tem duas opções principais:
1) Um índice por tenant.
Simples de raciocinar e reduz risco de acesso cruzado. Desvantagens: mais índices para gerenciar e atualizações de settings devem ser aplicadas de forma consistente.
2) Índice compartilhado + filtro por tenant.
Armazene um campo tenantId em cada documento e exija um filtro como tenantId = "t_123" em todas as buscas. Pode escalar bem, mas apenas se você garantir que toda requisição aplica o filtro (idealmente via chave scoped para que chamadores não possam removê-lo).
Mesmo que a busca esteja correta, resultados podem vazar campos que você não pretende mostrar (emails, notas internas, preços de custo). Configure o que pode ser retornado:
Faça um teste rápido de “pior cenário”: pesquise por um termo comum e confirme que nenhum campo privado aparece.
Se tiver dúvida se uma chave deve ficar no cliente, assuma “não” e mantenha a busca do lado do servidor.
Meilisearch é rápido quando você observa duas cargas: indexação (escrita) e consultas (leitura). A maior parte da lentidão misteriosa é resultado de competições por CPU, RAM ou disco entre essas cargas.
Carga de indexação pode subir quando você importa grandes batches, executa atualizações frequentes ou adiciona muitos campos pesquisáveis. Indexação é background, mas consome CPU e banda de disco. Se a fila de tasks crescer, buscas podem ficar lentas mesmo sem aumento de QPS.
Carga de consulta cresce com o tráfego, mas também com recursos: mais filtros, mais facetas, conjuntos de resultados maiores e maior tolerância a erros aumentam o trabalho por requisição.
I/O de disco é o culpado silencioso. Discos lentos (ou vizinhos barulhentos em volumes compartilhados) podem transformar “instantâneo” em “eventual”. NVMe/SSD costuma ser a base em produção.
Comece com um sizing simples: dê ao Meilisearch RAM suficiente para manter índices “quentes” e CPU suficiente para o QPS de pico. Depois separe preocupações:
Monitore um conjunto pequeno de sinais:
Backups devem ser rotina, não heroicos. Use o recurso de snapshot do Meilisearch em uma agenda, armazene snapshots fora da máquina e teste restaurações periodicamente. Para upgrades, leia as release notes, faça stage em um ambiente não-prod e planeje tempo de reindexação se mudanças de versão afetarem comportamento de indexação.
Se você já utiliza snapshots/rollback da sua plataforma (por exemplo, via workflow de snapshots/rollback do Koder.ai), alinhe o rollout da busca à mesma disciplina: snapshot antes de mudanças, verifique health checks e mantenha um caminho rápido para um estado conhecido bom.
Mesmo com uma integração limpa, problemas de busca tendem a cair em alguns grupos repetíveis. A boa notícia: o Meilisearch oferece visibilidade suficiente (tasks, logs, settings determinísticos) para depurar rapidamente — se você seguir um método.
filterableAttributes, ou os documentos armazenam o campo em forma inesperada (string vs array vs objeto aninhado).sortableAttributes/rankingRules podem estar elevando itens “errados”.Comece verificando se o Meilisearch aplicou com sucesso sua última mudança.
filter, depois sort, depois facets.Se você não consegue explicar um resultado, reduza temporariamente sua configuração: remova sinônimos, reduza ajustes de ranking e teste com um pequeno dataset. Problemas complexos de relevância são muito mais fáceis de detectar em 50 documentos do que em 5 milhões.
your_index_v2 em paralelo, aplique settings e reproduza uma amostra de queries de produção.filterableAttributes e sortableAttributes para que correspondam aos requisitos da UI.Related guides: /blog (search reliability, indexing patterns, and production rollout tips).
A pesquisa do lado do servidor significa que a consulta é executada no seu backend (ou em um serviço de busca dedicado), não no navegador. É a escolha certa quando:
Os usuários percebem quatro coisas imediatamente:
Se um desses faltar, as pessoas reescrevem consultas, rolando demais ou abandonando a busca.
Trate o Meilisearch como um índice de busca, não como sua fonte de verdade. Seu banco de dados cuida de gravações, transações e restrições; o Meilisearch armazena uma cópia dos campos selecionados otimizada para recuperação rápida.
Um modelo mental útil é:
Um padrão comum é um índice por tipo de entidade (por exemplo, products, articles). Isso mantém:
Se você precisa de um “buscar tudo”, pode consultar múltiplos índices e mesclar resultados no backend, ou criar um índice global dedicado depois.
Escolha uma chave primária que seja:
id, sku, slug)IDs estáveis tornam o indexamento idempotente: ao reenviar um upload, você não cria duplicatas porque as atualizações viram upserts.
Classifique cada campo por propósito para evitar indexação excessiva:
Manter esses papéis explícitos reduz resultados ruidosos e previne índices lentos ou inchados.
O indexamento é assíncrono: uploads de documentos criam uma tarefa, e os documentos ficam pesquisáveis somente após essa tarefa ser concluída com sucesso.
Um fluxo confiável é:
succeeded ou failedSe os resultados parecem desatualizados, verifique o status da task antes de debugar outra coisa.
Prefira muitos lotes menores em vez de um upload gigantesco. Pontos de partida práticos:
Lotes menores são mais fáceis de reenviar, depurar (achar registros problemáticos) e menos propensos a timeouts.
Dois alavancamentos de alto impacto são:
searchableAttributes: quais campos são pesquisados e em que prioridadepublishedAt, price ou popularityAborde na prática: pegue 5–10 consultas reais, grave os resultados principais “antes”, mude uma configuração e compare o “depois”.
A maioria dos problemas de filtro/ordenação vem de configuração ausente:
filterableAttributes para ser filtradosortableAttributes para poder ser ordenadoVerifique também o formato/tipo do campo nos documentos (string vs array vs objeto aninhado). Se um filtro falha, inspecione o último status de settings/task e confirme que os documentos indexados contêm os valores esperados.