Tutorials / Backend integrations / Set up Typesense search
πŸ“ Written ● Intermediate Updated 2026-05-13

Set up Typesense search

Open-source search engine, C++ core, native semantic + vector + geo search. Run as a single binary or hosted on Typesense Cloud. Algolia-like DX with no per-record fee.

Pick Typesense when

0
  • Pick Typesense when β€” you want open-source search with built-in vector embeddings, you outgrew Algolia's free tier, or your search includes geo (nearby places) / semantic (meaning-based) queries.
  • Pick Algolia for zero ops, polished UI, global edge by default.
  • Pick Meilisearch for similar shape, slightly different priorities (Rust vs C++; some DX trade-offs).
  • Pick Postgres FTS for ≀ 100K records with simple needs.

Typesense's distinguishing features: native vector search (no separate vector DB), built-in geo search, opinionated about defaults (less config than Algolia, more than Meilisearch).

Run locally with Docker

1
docker run -p 8108:8108 \
  -v $(pwd)/typesense-data:/data \
  -e TYPESENSE_API_KEY=your-strong-api-key \
  -e TYPESENSE_DATA_DIR=/data \
  typesense/typesense:latest \
  --enable-cors

Listens on http://localhost:8108. Health check:

curl http://localhost:8108/health
# {"ok":true}

Single binary version (no Docker): install docs β†—.

Production: pick deployment shape

2
  • Self-host on a VPS β€” same pattern as Meilisearch. systemd unit, Nginx + TLS in front. Cheapest; you maintain.
  • Typesense Cloud β†— β€” managed; clusters with auto-scale, global edge, on-call support. ~$20/mo starter.

This tutorial assumes Typesense Cloud or single-node self-hosted; Typesense supports HA clusters but that's a separate setup.

Create the API keys

3

The bootstrap admin key (you set it at startup) is for backend admin operations. For app code, create scoped keys:

curl http://localhost:8108/keys \
  -H 'X-TYPESENSE-API-KEY: your-strong-api-key' \
  -H 'Content-Type: application/json' \
  -d '{
    "description": "Search-only key",
    "actions": ["documents:search"],
    "collections": ["*"]
  }'

Copy the returned value β€” that's your client-side search key. Safe in browser. API keys docs β†—.

TYPESENSE_HOST=https://search.yourdomain.com
TYPESENSE_ADMIN_KEY=your-strong-api-key        # backend only
TYPESENSE_SEARCH_KEY=xxxxxxxxxxxxxxxxxxxxx     # safe in client

Install the SDK

4
npm install typesense

Other languages: Python, Ruby, PHP, Go, Java, .NET, Swift, Dart β†—.

Define a collection schema

5

Unlike Algolia / Meilisearch (which infer schema from documents), Typesense expects an explicit schema:

import Typesense from "typesense";

const client = new Typesense.Client({
  nodes: [{ host: "localhost", port: 8108, protocol: "http" }],
  apiKey: process.env.TYPESENSE_ADMIN_KEY,
});

await client.collections().create({
  name: "posts",
  fields: [
    { name: "title", type: "string" },
    { name: "body", type: "string" },
    { name: "tags", type: "string[]", facet: true },
    { name: "published_at", type: "int64" },
  ],
  default_sorting_field: "published_at",
});

Defining types upfront is more work than the auto-infer model β€” but you get better query performance and clear errors when data doesn't match. Collections docs β†—.

Index documents

6
// Single document
await client.collections("posts").documents().create({
  id: "post-123",
  title: "How to deploy to Vercel",
  body: "First, install the CLI...",
  tags: ["deploy", "vercel"],
  published_at: 1714521600,
});

// Bulk import (much faster for batches)
const jsonl = posts.map(p => JSON.stringify(p)).join("\n");
await client.collections("posts").documents().import(jsonl, { action: "upsert" });

JSONL bulk import handles 10K+ documents in a single request. Documents docs β†—.

Search

7
// Backend or frontend (with search-only key)
const result = await client.collections("posts").documents().search({
  q: "vercel deploy",
  query_by: "title,body",
  filter_by: 'tags:=["deploy"]',
  sort_by: "published_at:desc",
  per_page: 10,
});

console.log(result.hits);

The query_by parameter specifies which fields to search; filter_by adds Boolean filters; sort_by overrides default ranking.

Vector / semantic search (built in)

8

Typesense ships native vector search β€” embeddings, similarity, hybrid search β€” without adding a separate vector DB.

await client.collections().create({
  name: "articles",
  fields: [
    { name: "title", type: "string" },
    { name: "embedding", type: "float[]", num_dim: 384 },
  ],
});

// Hybrid search: keyword + vector
await client.collections("articles").documents().search({
  q: "deployment strategies",
  query_by: "title,embedding",
  vector_query: "embedding:([0.1, 0.2, ...], k:10)",
});

Combine keyword matching with semantic similarity in one query. Vector search docs β†—.

Typesense can also auto-generate embeddings via built-in models β€” pass embed config in the schema; Typesense fetches embeddings from OpenAI / Google PaLM / open-source models for you.

Geo search

9

Built-in lat/lng support β€” find records within X km of a point:

// Schema
{ name: "location", type: "geopoint" }

// Document
{ location: [37.7749, -122.4194] }

// Search "within 5km of San Francisco"
await client.collections("places").documents().search({
  q: "*",
  filter_by: "location:(37.7749, -122.4194, 5 km)",
});

No separate geo DB; works alongside text search in the same query.

InstantSearch UI library

10

Typesense ships an Algolia-compatible InstantSearch adapter β€” same React/Vue widgets:

npm install typesense-instantsearch-adapter react-instantsearch
import TypesenseInstantsearchAdapter from "typesense-instantsearch-adapter";

const adapter = new TypesenseInstantsearchAdapter({
  server: {
    nodes: [{ host: "search.yourdomain.com", port: 443, protocol: "https" }],
    apiKey: process.env.NEXT_PUBLIC_TYPESENSE_SEARCH_KEY,
  },
  additionalSearchParameters: { query_by: "title,body" },
});

import { InstantSearch, SearchBox, Hits } from "react-instantsearch";

export function Search() {
  return (
    <InstantSearch searchClient={adapter.searchClient} indexName="posts">
      <SearchBox />
      <Hits hitComponent={({ hit }) => <div>{hit.title}</div>} />
    </InstantSearch>
  );
}

Drop-in replacement for an Algolia searchClient. Adapter repo β†—.

Pricing reality

11

Self-hosted: free; you pay for the VPS ($5–10/mo for most projects).

Typesense Cloud: starts ~$20/mo for a small cluster. Scales linearly with cluster size, not per-record. Pricing β†—.

At Algolia's $25K/year tier, Typesense Cloud would be roughly $2-3K β€” order of magnitude cheaper.

Schemas are stricter than Algolia/Meilisearch. If you add a field to a document but not to the schema, Typesense rejects the document. This is good for production safety but feels stricter if you're used to "throw any JSON at it." Plan schemas; treat them like a DB migration.

Official references

What's next