Search-as-you-type with typo tolerance, faceting, and ranking — running globally on Algolia's network. Index your records via an API call; drop in the React/Vue/JS UI library. Sub-100ms queries from anywhere.
tsvector / tsquery) for simple needs already on your DB.Algolia's sweet spot: indie SaaS that wants search to feel like Linear or Stripe's docs with a few hours of work.
Sign up at algolia.com ↗. Build tier (free) covers 10K records + 10K requests/month — enough for a small app or doc site.
Dashboard shows your Application ID + four API keys:
ALGOLIA_APP_ID=ABCD1234
ALGOLIA_ADMIN_KEY=xxxxxxxxxxxxxxxxxxxxxxxx # backend only
ALGOLIA_SEARCH_KEY=xxxxxxxxxxxxxxxxxxxxxxxx # safe in browser
NEXT_PUBLIC_ALGOLIA_SEARCH_KEY=xxxxxxxxxxxxxx # ditto, for Next.js
An Algolia "index" is a collection of records. A record is a JSON object — anything you'd want to surface in search.
For a blog: each post is a record. For e-commerce: each product. For a SaaS: maybe one index for documents, another for users, another for tags.
Each record needs an objectID (your unique identifier — your DB primary key works). Algolia auto-indexes every other top-level field.
{
"objectID": "post-123",
"title": "How to deploy to Vercel",
"body": "First, install the CLI...",
"author": "Jane",
"tags": ["deploy", "vercel"],
"published_at": 1714521600
}
npm install algoliasearch
import { algoliasearch } from "algoliasearch";
const client = algoliasearch(
process.env.ALGOLIA_APP_ID,
process.env.ALGOLIA_ADMIN_KEY // admin key, BACKEND ONLY
);
// Save / replace a single record
await client.saveObject({
indexName: "posts",
body: {
objectID: "post-123",
title: "How to deploy to Vercel",
body: "First, install the CLI...",
tags: ["deploy", "vercel"],
},
});
// Bulk replace (faster for initial import)
await client.saveObjects({
indexName: "posts",
objects: arrayOfPosts,
});
Run this on a schedule (every N minutes) or on every DB write that touches indexable content. JS API client docs ↗.
Dashboard → your index → Configuration. The two settings that matter most:
title first, body second is typical. Docs ↗.popularity or published_at) to break ties. Ranking docs ↗.Or via API:
await client.setSettings({
indexName: "posts",
indexSettings: {
searchableAttributes: ["title", "body", "tags"],
customRanking: ["desc(published_at)"],
},
});
import { algoliasearch } from "algoliasearch";
const client = algoliasearch(
process.env.NEXT_PUBLIC_ALGOLIA_APP_ID,
process.env.NEXT_PUBLIC_ALGOLIA_SEARCH_KEY // search-only key; safe in browser
);
const { hits } = await client.searchSingleIndex({
indexName: "posts",
searchParams: { query: "vercel deploy" },
});
Use the search-only key, not admin. The search key is restricted to read operations; safe to ship in your JS bundle.
For instant search-as-you-type, don't roll your own. Algolia's InstantSearch library handles debouncing, faceting, pagination, and renders results.
React:
npm install algoliasearch react-instantsearch
import { liteClient } from "algoliasearch/lite";
import { InstantSearch, SearchBox, Hits } from "react-instantsearch";
const searchClient = liteClient(
process.env.NEXT_PUBLIC_ALGOLIA_APP_ID,
process.env.NEXT_PUBLIC_ALGOLIA_SEARCH_KEY
);
export function Search() {
return (
<InstantSearch searchClient={searchClient} indexName="posts">
<SearchBox />
<Hits hitComponent={({ hit }) => <div>{hit.title}</div>} />
</InstantSearch>
);
}
Equivalents: Vue InstantSearch ↗, vanilla JS InstantSearch ↗, Docusaurus DocSearch ↗ (free for open-source docs).
For "filter results by category / tag / price range," declare attributes as faceting:
await client.setSettings({
indexName: "posts",
indexSettings: {
attributesForFaceting: ["tags", "author", "filterOnly(published)"],
},
});
Then in InstantSearch:
import { RefinementList, HierarchicalMenu } from "react-instantsearch";
<RefinementList attribute="tags" />
<RefinementList attribute="author" />
The widgets render checkboxes and apply filters automatically. RefinementList docs ↗.
You probably don't want to manually push every record. Two common patterns:
saveObject. Simple, but doubles your latency.For Postgres, Algolia ships a Postgres connector ↗ that handles syncing automatically (paid feature).
author_bio if users won't search by it; it dilutes title/body matching.client.deleteObject() in Algolia. Easy to miss; surfaces as "I deleted that post but search still shows it."If costs become uncomfortable:
tsvector + GIN index is free and good enough.Both Meilisearch and Typesense ship Algolia-compatible APIs, so InstantSearch UI components plug right in with a different client.