There is no reason to pay for Algolia anymore
For most of the last decade, paying Algolia made sense. The alternative was running Elasticsearch, which meant a JVM, a cluster, mapping files and a relevance model you had to tune by hand before a search box felt anything like instant. Algolia gave you as-you-type search with typo tolerance and facets in an afternoon, and the bill was the price of not owning that problem.
That trade stopped holding up. Meilisearch is an open source (MIT) search engine built for the same job Algolia does: instant results on every keystroke, typo tolerance on by default, facets, synonyms and custom ranking. It is a single binary. And it does not care how many times your users press a key.
So the question is no longer "can I get Algolia-quality search without Algolia?" You can. The question is whether anything you use on Algolia is worth a bill that grows with every keystroke. For most apps the answer is no, and this post walks through the math and then the full setup: every Algolia setting you rely on, rebuilt on Meilisearch.
Contents
- What the meter actually charges you for
- What it costs at real sizes
- Meilisearch on Layerbase Pro
- Rebuilding your Algolia setup on Meilisearch
- Cutting over without a bad day
- Where Algolia still earns its bill
- FAQ
What the meter actually charges you for
Algolia's Grow plan includes 10,000 search requests and 100,000 records a month. Past that it charges $0.50 per 1,000 search requests and $0.40 per 1,000 records. Grow Plus keeps the record rate and charges $1.75 per 1,000 searches, which is what unlocks the AI features. Rates checked on 2026-11-03 at algolia.com/pricing.
Fifty cents per thousand sounds like nothing. The catch is what Algolia counts as a search request. In a search-as-you-type UI, every keystroke is its own billable request. A user typing "running shoes" is up to 13 requests, not one. Algolia's own Analytics dashboard collapses those into a single search, which is why the analytics number and the invoice number never agree.
Three more things push the meter around:
- Querying several indexes per keystroke multiplies it. Products, categories and articles in one search box, queried separately, is three requests per key.
- Sort orders cost records. Algolia sorts by price or date through replica indexes, and a standard replica is a full copy of its primary's records. A 50,000-record catalog with three sort orders bills as 200,000 records.
- Bots search too. Anything that scrapes a page with your search box, or hits your search endpoint directly, spends your requests. You find out on the invoice.
Algolia does document ways around this: debounce the input, batch indexes with multi-query, use virtual replicas. Those all help. But you are now writing code to keep a search box from costing too much. On a flat-priced engine, none of that code needs to exist.
What it costs at real sizes
Three typical setups on Algolia Grow, using the rates above. The search volume is billable requests, so keystrokes count:
| Setup | Requests / month | Algolia Grow / month | Algolia Grow / year | Meilisearch on Layerbase |
|---|---|---|---|---|
| Docs site, 10K records | 40,000 | $15 (30K billable requests) | $180 | $15/mo (Pro plan) |
| SaaS app, 100K records | 250,000 | $120 (240K billable requests) | $1,440 | $15/mo (Pro plan) |
| Store, 200K records, one sort replica | 1,000,000 | $615 (990K requests, 300K extra records) | $7,380 | Pro plus pool blocks at $10/mo each |
The first row is a tie, and if your docs site is open source, Algolia's DocSearch program may cover it for free. That row is not where the argument is.
The second row is where most growing products are. $1,440 a year for search on a product that also pays for a database, a cache and hosting, against $180 a year for a plan that includes the search engine and the database. And the Algolia number is the one that moves: a launch week, a Product Hunt spike or a crawler can double it, and you find out after the month closes.
The third row is about sizing, and I will get to it in the next section: a large catalog can need more memory than the base plan has. Even then, a couple of $10 pool blocks put you around $35 a month against $615.
Meilisearch on Layerbase Pro
Meilisearch runs on the Pro plan, $15/month. It is not on Free or Solo. Pro is up to 10 databases across the 19 engines on Layerbase Cloud, a 1.5 GB always-on pool with 25 GB of storage, 30-day rolling backups, and a 7-day free trial. The price does not change with searches, records or indexes.
What you get is upstream Meilisearch on a TLS endpoint, with the standard HTTP API. The official SDKs, @meilisearch/instant-meilisearch and scoped keys all work, because nothing about the API is changed. The connection panel gives you three keys: a Search key that is safe in the browser, and Admin and Master keys for server code only. That is the same split as Algolia's search-only and admin API keys.
On sizing: how much memory an index needs depends on how many documents it holds, how wide they are and how many attributes are filterable, so check the index size after your first import rather than trusting a rule of thumb. If it outgrows the pool, that calls for $10/month pool blocks (each adds 1 GB RAM, 1 vCPU and 25 GB) or a dedicated server. Meilisearch Cloud alternatives goes through exactly where the pool runs out.
Two things you get here that Algolia does not offer. Your search index lives in the same account as its source database, so the job that keeps them in sync talks to two databases on one bill instead of two vendors. And Meilisearch branches: a copy-on-write clone of the index for a preview deploy or a relevance experiment, ready in seconds, deleted when the PR closes.
Rebuilding your Algolia setup on Meilisearch
The rest of this post is the setup guide. It assumes a product catalog index called products, because that is the case that uses the most Algolia features. If you want your records and settings copied over automatically, the Algolia migration wizard reads your index once with an Admin key and does steps 2 and 3 for you. Migrating from Algolia to Meilisearch has the same migration as a script you can read and run yourself. What follows is the setting-by-setting map, so you know what each Algolia setting turned into and can tune it.
The examples use the official JavaScript client:
pnpm add meilisearchStep 1: Create the database
Create a Meilisearch database from Layerbase Cloud and copy the host and the three keys from its connection panel into your server environment:
MEILI_HOST=https://your-host.cloud.layerbase.dev
MEILI_ADMIN_KEY=... # server only, like your Algolia Admin API key
MEILI_SEARCH_KEY=... # browser safe, like your Algolia Search-Only API keyServer code gets an admin client:
import { Meilisearch } from 'meilisearch'
export const meili = new Meilisearch({
host: process.env.MEILI_HOST!,
apiKey: process.env.MEILI_ADMIN_KEY!,
})Step 2: Create the index with the same key
Algolia's records key off objectID. If your records already have one, keep it as the primary key so every upsert and delete in your sync code keeps working unchanged:
await meili.createIndex('products', { primaryKey: 'objectID' }).waitTask()Meilisearch primary key values must be letters, numbers, - and _. Most objectIDs already are. If yours contain slashes or spaces, map them to a clean id field and use that instead.
Step 3: Recreate your index settings
This is where your Algolia relevance configuration lives. Here is the map from Algolia setting to Meilisearch setting:
| Algolia setting | Meilisearch setting |
|---|---|
searchableAttributes (ordered by importance) | searchableAttributes (same order rule) |
customRanking: ['desc(popularity)'] | rankingRules ending in 'popularity:desc' |
attributesForFaceting | filterableAttributes |
attributeForDistinct + distinct: true | distinctAttribute |
synonyms | synonyms |
minWordSizefor1Typo, minWordSizefor2Typos | typoTolerance.minWordSizeForTypos |
disableTypoToleranceOnAttributes | typoTolerance.disableOnAttributes |
removeStopWords | stopWords (you supply the list) |
attributesToRetrieve | displayedAttributes |
paginationLimitedTo (default 1000) | pagination.maxTotalHits (default 1000) |
maxValuesPerFacet | faceting.maxValuesPerFacet |
replicas for sort orders | sortableAttributes plus sort at query time |
And here it is as one settings call for a typical catalog:
await meili
.index('products')
.updateSettings({
searchableAttributes: ['name', 'brand', 'category', 'sku', 'description'],
filterableAttributes: ['brand', 'category', 'in_stock', 'price', 'tenant_id'],
sortableAttributes: ['price', 'created_at', 'popularity'],
rankingRules: [
'words',
'typo',
'proximity',
'attribute',
'sort',
'exactness',
'popularity:desc',
],
distinctAttribute: 'product_group_id',
synonyms: {
tee: ['t-shirt'],
't-shirt': ['tee'],
sneakers: ['trainers', 'running shoes'],
},
typoTolerance: {
minWordSizeForTypos: { oneTypo: 4, twoTypos: 8 },
disableOnAttributes: ['sku'],
},
stopWords: ['the', 'a', 'an', 'of'],
faceting: { maxValuesPerFacet: 100 },
pagination: { maxTotalHits: 1000 },
})
.waitTask()A few notes on how the two engines differ:
- Ranking. Algolia runs a fixed tie-break formula and puts
customRankingat the end of it. Meilisearch exposes the whole sequence asrankingRules. Appendingpopularity:descafter the six defaults gives you the same behavior as Algolia's custom ranking: text relevance first, business metric as the tie-break. Move it earlier only if you want popularity to beat a better text match. - Facets. Algolia uses one setting for filtering and faceting. In Meilisearch, anything in
filterableAttributescan be filtered on and returned as a facet. Algolia'sfilterOnly(x)andsearchable(x)modifiers drop away. - Synonyms. Meilisearch synonyms are one-way. For Algolia's two-way synonyms, list each direction, as with
teeandt-shirtabove. Alternative corrections and placeholders have no equivalent. - Typo tolerance on numbers. Put SKUs and part numbers in
disableOnAttributes, as on Algolia. Otherwise a typo in a part number can match a different part.
Step 4: Replace replicas with a sort parameter
On Algolia, "sort by price, low to high" means a replica index called something like products_price_asc, with its own copy of every record. On Meilisearch it is one index and a query parameter, because price is in sortableAttributes:
const results = await meili.index('products').search('jacket', {
sort: ['price:asc'],
})Every replica you delete is records you stop paying for. In the store row of the cost table, the one price replica alone added 200,000 billed records.
Step 5: Search parameters
The query side maps almost one to one. An Algolia search like this:
// Algolia
index.search('jacket', {
filters: 'brand:Patagonia AND price < 300',
facets: ['brand', 'category'],
hitsPerPage: 20,
page: 0,
attributesToHighlight: ['name'],
highlightPreTag: '<mark>',
highlightPostTag: '</mark>',
})becomes:
// Meilisearch
meili.index('products').search('jacket', {
filter: 'brand = "Patagonia" AND price < 300',
facets: ['brand', 'category'],
hitsPerPage: 20,
page: 1,
attributesToHighlight: ['name'],
highlightPreTag: '<mark>',
highlightPostTag: '</mark>',
})Two things to watch. Meilisearch pages start at 1, not 0. And filter syntax is SQL-like (brand = "Patagonia"), not brand:Patagonia. Facet counts come back in facetDistribution, and highlighted text in each hit's _formatted field.
If you search several indexes per keystroke, meili.multiSearch({ queries: [...] }) sends them in one request. On Algolia that saves money. On Meilisearch it only saves round trips.
Step 6: Geo search
Algolia stores coordinates in _geoloc. Meilisearch uses _geo with the same lat and lng keys, so it is a rename when you index:
const doc = { objectID: 'store_17', name: 'Downtown', _geo: { lat: 30.2672, lng: -97.7431 } }Add _geo to both filterableAttributes and sortableAttributes, and Algolia's aroundLatLng with aroundRadius becomes a filter plus a sort:
meili.index('stores').search('', {
filter: '_geoRadius(30.2672, -97.7431, 5000)',
sort: ['_geoPoint(30.2672, -97.7431):asc'],
})The radius is in meters, the same as Algolia's.
Step 7: Scoped keys and secured API keys
Algolia has two key tools that multi-tenant apps rely on, and Meilisearch has both.
Restricted keys (a key limited to certain indexes and actions) are Meilisearch API keys. Create one with the admin client:
const storefrontKey = await meili.createKey({
name: 'storefront',
description: 'Search only, products index',
actions: ['search'],
indexes: ['products'],
expiresAt: null,
})
// One key per storefront app. On a single-tenant index, storefrontKey.key can
// go to the browser. On a multi-tenant index, keep it on the server and send
// the browser only tenant tokens (below).Secured API keys (Algolia's generateSecuredApiKey, which bakes a filter like tenant_id:42 into a key) are tenant tokens in Meilisearch. You sign them on your server, they cost no API call, and the filter is enforced on every search made with the token:
import { generateTenantToken } from 'meilisearch/token'
export async function searchTokenForTenant(tenantId: number) {
return generateTenantToken({
apiKey: process.env.STOREFRONT_KEY!,
apiKeyUid: process.env.STOREFRONT_KEY_UID!,
searchRules: { products: { filter: `tenant_id = ${tenantId}` } },
expiresAt: new Date(Date.now() + 60 * 60 * 1000),
})
}The token is signed with a search key, here the key and uid from the createKey call above stored as STOREFRONT_KEY and STOREFRONT_KEY_UID. That key is the signing secret, so in a multi-tenant app it never leaves your server: anyone holding it can search every tenant, or sign a token with any filter they like. The browser gets only the token your server returns. The filtered attribute also has to be in filterableAttributes, which is why tenant_id is in the Step 3 settings.
Step 8: Keep the index in sync
Your app already pushes changes to Algolia from somewhere: a model hook, a queue worker, a nightly job. The calls map one to one:
| Algolia | Meilisearch |
|---|---|
saveObjects | addDocuments (replace by key) |
partialUpdateObjects | updateDocuments (merge fields) |
deleteObjects | deleteDocuments(ids) |
clearObjects | deleteAllDocuments |
export async function syncProduct(product: Product) {
await meili.index('products').updateDocuments([toSearchDocument(product)])
}
export async function removeProduct(objectID: string) {
await meili.index('products').deleteDocument(objectID)
}Writes in Meilisearch are asynchronous tasks, like Algolia's. Your sync code does not need to wait on them. Call .waitTask() only in scripts and tests that read back right after writing.
If the source of truth is a Postgres database on the same Layerbase account, this job now talks to two databases that live together, which is one less vendor in the path when something goes stale.
Step 9: Swap the frontend
If your UI is built on React InstantSearch or Vue InstantSearch, the widgets stay. Only the client changes:
pnpm add @meilisearch/instant-meilisearch// Before:
// import { liteClient as algoliasearch } from 'algoliasearch/lite'
// const searchClient = algoliasearch('APP_ID', 'SEARCH_ONLY_KEY')
import { instantMeiliSearch } from '@meilisearch/instant-meilisearch'
const { searchClient } = instantMeiliSearch(
'https://your-host.cloud.layerbase.dev',
'YOUR_SEARCH_KEY_OR_TENANT_TOKEN',
)
// <InstantSearch indexName="products" searchClient={searchClient}> and every
// <SearchBox>, <Hits>, <RefinementList> and <SortBy> inside it stay as they are.<SortBy> items that pointed at replica index names now point at products:price:asc style values, which the adapter turns into a Meilisearch sort. You can also delete the debounce you added to keep the Algolia bill down, though a short debounce still saves your users some network chatter.
Cutting over without a bad day
The order I use:
- Build the Meilisearch index next to Algolia, either from the wizard or with your sync job doing a full backfill. Algolia stays live and untouched.
- Point your sync job at both for a while, so the two indexes stay current together.
- Pull your top 50 queries from Algolia Analytics and run each one against both engines. Expect the results to be equivalent, not identical. Two engines rank close calls differently. Tune
searchableAttributesorder andrankingRuleswhere the order matters for your business, and try relevance changes on a branch of the index instead of on the one serving traffic. - Flip the frontend client behind a feature flag. Watch it for a few days.
- Turn off Algolia writes, then cancel the plan.
The only one-way step is the last one. Everything before it can be rolled back by switching the client again.
Where Algolia still earns its bill
Some Algolia features have no Meilisearch equivalent, and if your business depends on one, it is worth paying for:
Query Rules and merchandising. If your merchandising team pins products to specific queries, runs seasonal boosts and rewrites queries from a dashboard without engineering involved, Algolia's rule engine is real value. On Meilisearch that becomes code you write.
Personalization, Recommend, A/B testing and search analytics. These are Algolia's paid layer. If a team reviews search analytics every week and runs relevance experiments as A/B tests, you would be rebuilding a product, not a search box.
Multi-region and contractual SLAs. Algolia replicates search across regions and signs enterprise SLAs. A single Meilisearch instance does not.
And if you are on Algolia's free tier or DocSearch, you are not paying for Algolia, so there is nothing to save. This post is for the invoice that grows every month.
For everyone else, the search box, the facets, the typo tolerance, the custom ranking, the sort orders and the tenant-scoped keys, all the parts you actually built on, are covered.
FAQ
Is Meilisearch on the Layerbase Solo plan?
No. Meilisearch is a Pro-tier engine, and Pro is $15/month with a 7-day free trial. Solo is $5/month and, like Free, covers the Standard engines such as Postgres, MariaDB and Valkey. The Pro plan includes up to 10 databases, so the Postgres your search index is built from can live in the same plan.
How much can I save moving from Algolia to Meilisearch?
It depends on volume. A SaaS app with 100,000 records and 250,000 billable search requests a month pays about $120/month on Algolia Grow, or $1,440 a year. On Layerbase, Pro is $15/month, so the same index costs $180 a year. A small docs site inside Algolia's free allowances saves nothing.
Do I have to rewrite my InstantSearch UI?
No. @meilisearch/instant-meilisearch is a drop-in search client for React InstantSearch and Vue InstantSearch. You change the client, and your widgets stay. Code that calls the Algolia client directly needs its call sites updated, mostly filter syntax and page numbering.
Does Meilisearch have Algolia's secured API keys?
Yes, as tenant tokens. You sign a token on your server with a search key and attach a filter such as tenant_id = 42. Every search with that token is restricted to that filter, and generating it costs no API call.
Does Meilisearch have typo tolerance like Algolia?
Yes, on by default, with the same knobs: minimum word length for one and two typos, and attributes or words where typos are turned off.
Will my search results come back in the same order?
Close, not identical. Both engines rank text relevance first and your business metric as a tie-break, but they settle close calls differently. Compare your top queries side by side and tune ranking rules where the order matters.
Where to start
If your Algolia bill went up last month, start with the Algolia migration wizard: it copies one index into a managed Meilisearch database on a 7-day Pro trial, writes nothing back to Algolia, and hands you the frontend snippet with your search key filled in. Then run your top queries against both and decide with real results in front of you.
If you are still comparing options, Algolia vs Meilisearch goes feature by feature, and Algolia alternatives covers Typesense and Postgres full-text search too. And Getting started with Meilisearch builds a search index from scratch if you are not migrating anything.
Keep reading
- Algolia vs MeilisearchA 2026 comparison of Algolia and Meilisearch: ranking models, typo tolerance, faceting, hybrid search, analytics, merchandising, limits, licensing, and what each one costs at 10K, 100K and 1M records.
- Algolia alternatives in 2026: Meilisearch is the cheap drop-inAlgolia is excellent and expensive. Meilisearch gives you 90 percent of the developer experience at a fraction of the price, with a managed option that does not charge per search. Here is the honest comparison.
- Migrating from Algolia to MeilisearchA practical guide to moving search from Algolia to Meilisearch: what maps cleanly, what does not, how to copy records and settings, and the frontend swap.
- Getting Started with MeilisearchBuild instant, typo-tolerant search with Meilisearch and TypeScript. Learn why database queries fail on misspelled input and how Meilisearch fixes that fast.