All the parts

Build · Add powers

Search

How do people find things in my app?

What it is

Search means typing a few words and getting the best matches, even with typos. For small apps your database can do it. For bigger ones you use a search engine, which keeps its own copy of your data in a form built for fast lookups.

It is the index at the back of a book: you look up a word and jump to the pages, instead of reading every page.

Add it when Users must find items in a large list, and exact matching or filters are not enough.

It can wait when You have a few hundred rows. A simple filter or LIKE query in your database is fine.

1 Which one should I pick?

Answer what you can. The ranking updates as you go, and you can ignore it if you disagree.

How much data do you have?
Who will run it?
What matters most right now?

Most people start with

2 Side by side

Three pips is strong, one is weak. Pick a row to read about it below.

OptionQuick to set upCheap while smallEasy to leaveRoom to growPrice
Free; part of your database
Free tier, then pay per search and records
Free to self-host, or pay for their cloud
Free to self-host; managed versions are pay as you go

3 Look closer, then wire it in

Standard

Postgres full-text search

Search built into the database you already have. No extra service.

Pick it when You already use Postgres and have a small or medium amount of data.

Skip it if You need typo tolerance, instant as-you-type results or fancy ranking.

  • Nothing new to run or pay for
  • Always in sync, it is the same data
  • Plain LIKE '%x%' works for tiny tables
  • Basic typo handling
  • Ranking and tuning take SQL skill
Quick to set up
Cheap while small
Easy to leave
Room to grow

PriceFree; part of your database

How to connect it

  1. Add a generated column that turns your text into a search vector.
  2. Add an index on that column so searches stay fast.
  3. Query with a search term and sort by rank.
  4. Call that query from an API route as the user types.
Put these in your .env file
  • DATABASE_URL
search.sql
alter table posts add column fts tsvector
  generated always as (to_tsvector('english', title || ' ' || body)) stored;

create index posts_fts_idx on posts using gin (fts);

select id, title from posts
where fts @@ websearch_to_tsquery('english', 'red shoes')
order by ts_rank(fts, websearch_to_tsquery('english', 'red shoes')) desc
limit 20;

4 Watch it work

Press play, or step through one message at a time.

Press Play to watch it run · 6 steps

Every write also updates the index. Every search reads from the index, not the database.

Keeping search in syncEvery write also updates the index. Every search reads from the index, not the database.Save new productCopy it into the indexUser types: red shoQuery: red shoMatches ranked by relevanceShow the results
  • Client
  • Service
  • Database
  • Search index
Text description
  1. Your app → Your database: Save new product
  2. Your app → Search index: Copy it into the index
  3. Browser → Your app: User types: red sho
  4. Your app → Search index: Query: red sho
  5. Search index replies to Your app: Matches ranked by relevance
  6. Your app replies to Browser: Show the results

5 Mistakes to skip

  • Adding a search engine before you need one.

    Try a plain LIKE query or Postgres full-text search first. They are often enough.

  • Forgetting the index is a copy of your data.

    Update or delete the index record every time the real record changes, and re-index everything if they drift.

  • Putting the admin key in the browser.

    Use the search-only key in the browser and keep the admin key on the server.

See where it sits in a whole app

The stack builder draws your product with search in it and animates a request through it.

Open the stack builder

Works closely with