Algolia's free tier caps out fast, and its paid plans bill per search + per record — the kind of cost that sneaks up on you right when a product actually starts getting traffic. If you're building a search-as-you-type feature (docs site, product catalog, internal admin tool) and don't want that bill, Typesense is worth a serious look.
What Typesense actually is
Typesense is an open-source, C++ search engine built specifically for the "instant search" use case — typo-tolerant, sub-50ms, faceted search behind a clean REST API. It's not trying to be a general-purpose data platform; it does one thing (search-as-you-type) and does it fast. Official clients exist for JS/TS, Python, PHP, Ruby, Go, Java, and .NET, plus a drop-in InstantSearch.js adapter if you're migrating off Algolia's own UI library.
If you've looked at Meilisearch already: they're close cousins in the same category (both open-source, both typo-tolerant, both REST-first). Typesense leans more toward faceting and filtering depth (its query DSL for filters/facets is more expressive), Meilisearch leans toward out-of-the-box simplicity. Worth trying both against your actual dataset before committing — they're similar enough that the difference usually comes down to your specific filtering needs, not raw speed.
The two things that bite people self-hosting it
No auth by default. Typesense doesn't ship with a locked-down default — you set an API key at boot and every request needs X-TYPESENSE-API-KEY. Skip this on a publicly reachable box and your index is wide open, readable and writable by anyone.
No persistent volume = ephemeral index. Typesense writes its index to --data-dir on disk. Run it in a plain container with no volume and every redeploy silently wipes your search index back to zero. Nothing errors — the service comes back up healthy, just empty.
There's a third, sneakier one if you're running it anywhere with a CPU limit (Docker with --cpus, Kubernetes with a CPU request/limit, or any cloud platform that caps a container's vCPUs): Typesense's default thread-pool sizing reads the physical host's core count, not your container's actual allocation. On a shared host with a low vCPU cap this oversubscribes the pid limit and the process straight-up refuses to boot — std::system_error: Resource temporarily unavailable. Passing --thread-pool-size explicitly, capped to whatever you actually got, fixes it. Nowhere in Typesense's docs is this obviously your problem until you hit it.
Running it yourself
docker run -p 8108:8108 -v ts-data:/data \
typesense/typesense:30.2 \
--data-dir=/data --api-key=your-secret-key --thread-pool-size=4
Then:
# create a collection
curl -X POST 'http://localhost:8108/collections' \
-H 'X-TYPESENSE-API-KEY: your-secret-key' -H 'Content-Type: application/json' \
-d '{"name":"docs","fields":[{"name":"title","type":"string"},{"name":"pts","type":"int32"}]}'
# index a document
curl -X POST 'http://localhost:8108/collections/docs/documents' \
-H 'X-TYPESENSE-API-KEY: your-secret-key' -H 'Content-Type: application/json' \
-d '{"title":"hello world","pts":42}'
# search — typo-tolerant, "helo wrld" still matches
curl 'http://localhost:8108/collections/docs/documents/search?q=helo+wrld&query_by=title' \
-H 'X-TYPESENSE-API-KEY: your-secret-key'
That's the whole thing — no schema migrations, no separate indexing pipeline, just POST documents and query.
The one-click path
Full disclosure: I maintain a Railway template for this and get a kickback if you deploy through it. It wires up the two footguns above by default — API key auto-generated as a Railway secret (never a blank/default value sitting in your env), a persistent volume mounted at /data so redeploys don't wipe your index, and the thread-pool size pre-capped so it doesn't crash-loop on boot the way a naive docker run would on a constrained host: https://railway.com/deploy/typesense-instant-search-algolia-alterna?referralCode=Z1xivh&utm_medium=integration&utm_source=template&utm_campaign=inventory
If you'd rather not go through a referral link, the raw docker run command above with a volume attached gets you the same result on any Docker host — the template is just the same public image with the footguns pre-wired.
When it's not the right call
If you're already deep in Postgres and only need "good enough" search over a few thousand rows, pg_trgm or full-text search extensions might genuinely be simpler than standing up a whole separate service. Typesense earns its keep once you need real typo-tolerance, faceting, and search-as-you-type latency that a database extension isn't built for.
Top comments (0)