Someone types three letters into your search box, gets nothing back, and leaves. You never see it happen. You just see the bounce in the analytics weeks later and blame the landing page.
Search isn't a feature you bolt on at the end. On a shop or a booking site it's the highest intent thing a person can do. They're telling you exactly what they want. Make them wait for it, or punish them for one fat fingered letter, and you've thrown away a sale you'd already half made.
We've built search on a few products now. The one that taught us the most was a parking spot booking app. Here's what we changed, what broke first, and the numbers that made the case.
We started on the database, like everyone does
The first version of that search was a database query. Filters, a couple of joins, distance math, an ORDER BY. It worked. For a while.
Then the map got busy and it didn't. We were scrapping to keep that query under 500ms, and every filter a user added made it heavier. Under load it was worse. You can index your way out of some of that, and we tried, but you're polishing the wrong tool. A relational database is not built to rank fuzzy text and sort ten thousand points by distance while someone drags a map around. It'll do it. It won't do it fast.
That's the honest version. We spent a week making the wrong thing slightly less slow before admitting it was the wrong thing.
What Meilisearch actually is
Meilisearch is an open source search engine written in Rust. You feed it documents, it builds an index, it answers queries in a few dozen milliseconds. Typo tolerance is on by default: a five character word forgives one typo, a nine character word forgives two, so "phnoe" finds "phone" and you configure nothing. Faceted filters, synonyms, and geo search are all in the box, behind a clean REST API.
The number that matters is under 50ms. Not a benchmark you hit on a good day. The default. That's the whole gap between search that feels instant and search that feels like waiting.
Keep it an index, not a second database
Here's the opinion I'll defend. Meilisearch is your search index. It is not your database. Don't let it drift into being one.
When a query runs, Meilisearch hands back the primary keys of the matching documents. That's it. In Laravel, Scout takes those keys and pulls the full records straight from your database with one whereIn. You search in Meili, you read from Postgres. The index and the source of truth stay separate.
We did that on purpose, and I'd do it again. Every field you copy into the index is another field living outside your database, in another system, that you now have to secure and reason about. Push your whole model in there and two things happen: the index bloats and slows down, and you've quietly scattered sensitive data across a service that was only ever meant to find a row. Put in what search needs to match and rank. Leave the rest in the database where it belongs. Scout makes that the lazy path, which is rare and worth appreciating.
Where it earned its money: the map
The full text side you can almost take for granted until you hit the thing it solves cleanly. For us that was the map.
The interaction sounds trivial and is a pain to build well. Drop a pin, set a radius, get every free spot inside it, nearest first, and keep it updating as you shove the map around. The radius goes to 8000 meters, so a busy district is a lot of candidate spots to sort on every little pan.
Meilisearch does geo out of the box. You store a _geo field on each document, mark it filterable and sortable, and _geoRadius(lat, lng, meters) gives you everything inside the circle. Sort by _geoPoint(lat, lng):asc and results come back ordered by distance, each carrying a _geoDistance in meters. No PostGIS. No hand written haversine buried in a query. No arguing with the query planner.
What the client noticed first wasn't a feature at all. The map just felt fluent. Pan and search stopped being two slow steps and became one motion. Nobody sends a thank you note for that. They just stop leaving, which is the same thing measured differently.
The number
This is the part for the skeptical engineer, because I was one.
Before: that database query, scrapping to stay under 500ms, worse under load. After: 35ms average. Not a cherry picked best case, the average. The complex query that used to sit near half a second now answers before the user's finger leaves the map. That's better than a tenfold cut, and it came from moving the work to a tool built for it, not from grinding harder on the tool that wasn't.
People assume a gain like that needs a rewrite. It didn't. The heavy lifting is taking the search load off the database and putting it on an engine that does one job.
The index stays in sync on its own
The usual objection to a separate search engine is the obvious one. Now you've got two stores and they drift.
With Laravel Scout that mostly goes away. Add a trait to the Eloquent model, say which fields are searchable, and Scout keeps the index current as rows are created, updated, and deleted. Updates ride your queue, so indexing never blocks a web request. Soft deletes are handled. Day to day, you stop thinking of the index as a thing you maintain. You change a record, the index follows. That's the point.
Where vectors come in
Typo tolerant full text covers most of what people type. But intent is messier than keywords. In the parking app people search across a jumble: a street, a tag, a property of the spot, sometimes the spot's own name. Those queries don't line up neatly with the exact words sitting in your data, and no amount of typo tolerance saves a query that shares no words with the record it should match.
That's where semantic search earns its place. Since 1.3, Meilisearch stores vector embeddings next to your documents and can run hybrid search: keyword matching and meaning based matching together. A query that shares no words with a record can still find it because they're close in meaning. You make the embeddings with a model you pick, Meili holds them and searches them. The move I'd recommend: ship solid full text first, add semantic on top when the messy queries start showing up in your logs. You don't tear anything out to get there.
Why any of this shows up in sales
Plainly. A search that's slow, or that returns nothing the second someone mistypes, is a leak. Nobody files a complaint. They leave, and you never find out why.
Since the switch, a zero result search means there genuinely is no matching record. Not one wrong letter. Not a query phrased a little differently than the data. That's the whole game. The box should return what the person meant, fast enough they never once think about the box. Every search that finds the right thing is a person who stayed. A good share of the people who stay, buy.
Fast, forgiving search never feels like a growth lever, because when it works it's invisible. Which is exactly why it gets skipped.
Where Conimex IT comes in
If your site search is a LIKE query that punishes typos, or your map stutters, or your analytics are full of searches that came back empty, that's fixable, and it rarely needs the rebuild you're bracing for. We build search for shops and web apps on Meilisearch and Laravel: full text with typo tolerance and synonyms, geo search for maps and location, clean Scout indexing that tracks your database, and hybrid semantic search when the queries need to match intent and not just words. If that sounds like a leak you'd rather close, get in touch and we'll take a look at what your search is quietly costing you.
