Typesense Next.js: Search-UI mit InstantSearch bauen
Eine produktive Suchoberfläche im Next.js App Router braucht drei Bausteine: einen Search-Server, eine UI-Bibliothek und ein sauberes SSR-Pattern. Typesense-Next.js-Setups nutzen dafür den offiziellen typesense-instantsearch-adapter, der die Brücke zu Algolias InstantSearch.js schlägt.
Dieser Leitfaden zeigt die Architektur, die benötigten Pakete, die Adapter-Konfiguration und die typischen Stolperfallen rund um Hydration, SSR und scoped API Keys. Wenn Sie noch keinen Server betreiben, lesen Sie zuerst unseren Leitfaden zum Thema „Typesense installieren“.
Key Takeaways
- Der
typesense-instantsearch-adapterverbindet Typesense mitreact-instantsearch - Im App Router laufen Server Components und Client Components parallel
- SSR funktioniert über
getServerState - Scoped API Keys gehören ins Frontend, niemals der Admin Key
- Das offizielle Showcase-Repository deckt App Router + SSR vollständig ab
- Für Headless Commerce ist das Pattern heute ein De-facto-Standard
Wie verbindet man Next.js mit Typesense?
Sie verbinden Next.js mit Typesense, indem Sie den typesense-instantsearch-adapter als Search Client konfigurieren und anschließend mit react-instantsearch koppeln.
Die Architektur sieht typischerweise so aus:
Browser | v Next.js App Router | v Typesense Cluster
Im App Router rendert Next.js das Layout serverseitig. Die eigentliche Suchoberfläche läuft als Client Component.
Direct-Browser-Pattern
Der Browser spricht Typesense direkt an.
Vorteile:
- geringere Latenz
- weniger Serverlast
- einfachere Architektur
Nachteile:
- Key-Management wichtig
- eingeschränkte zentrale Kontrolle
Wichtig: Nur Search-Only-Keys oder Scoped Keys verwenden.
Proxy-Pattern via Route Handler
Hier routet ein Next.js Route Handler die Suchanfragen an Typesense weiter.
Vorteile:
- zentrale Rechteprüfung
- Rate Limiting
- Logging
- einfachere Mandantenlogik
Nachteile:
- zusätzlicher Netzwerk-Hop
- etwas höhere Latenz
In B2B-Setups mit Login und Kundengruppen ist dieses Pattern meist robuster.
Welche Pakete benötigen Sie?
npm install \ typesense \ typesense-instantsearch-adapter \ react-instantsearch \ react-instantsearch-router-nextjs
Die Aufgaben der Pakete:
| Paket | Zweck |
| typesense | offizieller API-Client |
| typesense-instantsearch-adapter | Adapter zu InstantSearch |
| react-instantsearch | Search-UI-Komponenten |
| react-instantsearch-router-nextjs | URL-Synchronisation |
Wie erstellen Sie eine Typesense Collection?
Vor der UI benötigen Sie ein Schema.
import Typesense from "typesense";
const client = new Typesense.Client({
nodes: [
{
host: "search.example.com",
port: 443,
protocol: "https",
},
],
apiKey: process.env.TYPESENSE_ADMIN_KEY!,
});
await client.collections().create({
name: "products",
fields: [
{ name: "title", type: "string" },
{ name: "description", type: "string" },
{ name: "brand", type: "string", facet: true },
{ name: "categories", type: "string[]", facet: true },
{ name: "price", type: "float", facet: true },
{ name: "in_stock", type: "bool", facet: true },
],
default_sorting_field: "price",
});
Felder mit facet: true erscheinen später als Filter.
Schema für Produktdaten
Ein typisches Produktschema enthält:
- Titel
- Beschreibung
- Marken
- Kategorien
- Preise
- Lagerbestand
Im B2B kommen häufig hinzu:
- Kundengruppen
- Hersteller-IDs
- Artikelnummern
- technische Spezifikationen
Facettenfelder definieren
Alle filterbaren Felder erhalten facet: true.
Typische Facetten:
- Marke
- Kategorie
- Material
- Preis
- Verfügbarkeit
Dokumente importieren
Nach dem Schema importieren Sie Dokumente per documents().import().
Wie konfigurieren Sie den InstantSearch-Adapter?
Die Adapter-Konfiguration ist das Herzstück der Integration.
"use client";
import TypesenseInstantsearchAdapter from "typesense-instantsearch-adapter";
export const searchClient =
new TypesenseInstantsearchAdapter({
server: {
apiKey:
process.env
.NEXT_PUBLIC_TYPESENSE_SEARCH_KEY!,
nodes: [
{
host:
process.env
.NEXT_PUBLIC_TYPESENSE_HOST!,
port: 443,
protocol: "https",
},
],
cacheSearchResultsForSeconds: 60,
},
additionalSearchParameters: {
query_by:
"title,description,brand,categories",
query_by_weights: "4,2,2,1",
num_typos: 2,
},
}).searchClient;
Server-Verbindung
Die Nodes definieren Host, Port und Protokoll.
Search-Only-Key statt Admin-Key
Im Frontend darf ausschließlich ein Search-Only-Key oder Scoped Key verwendet werden.
query_by, query_by_weights und num_typos
query_by definiert die durchsuchbaren Felder.
query_by_weights priorisiert wichtige Felder.
num_typos steuert die Tippfehler-Toleranz.
Wie bauen Sie die Search-UI mit React InstantSearch?
react-instantsearch liefert fertige Widgets.
"use client";
import {
InstantSearch,
SearchBox,
Hits,
RefinementList,
Pagination,
} from "react-instantsearch";
import { searchClient } from "./search-client";
export function ProductSearch() {
return (
<InstantSearch
searchClient={searchClient}
indexName="products"
>
<SearchBox placeholder="Produkte suchen" />
<div className="grid grid-cols-4 gap-6">
<aside>
<RefinementList attribute="brand" />
<RefinementList attribute="categories" />
</aside>
<main className="col-span-3">
<Hits hitComponent={ProductHit} />
<Pagination />
</main>
</div>
</InstantSearch>
);
}
function ProductHit({
hit,
}: {
hit: {
title: string;
price: number;
};
}) {
return (
<article>
<h3>{hit.title}</h3>
<p>{hit.price.toFixed(2)} EUR</p>
</article>
);
}
SearchBox
Die SearchBox sendet Suchanfragen direkt an Typesense.
Hits
Hits rendert die Trefferliste.
RefinementList
Facettenfilter werden über RefinementList umgesetzt.
Pagination
Pagination ermöglicht große Trefferlisten performant darzustellen.
Wie funktioniert SSR im Next.js App Router?
SSR läuft über getServerState.
import { getServerState }
from "react-instantsearch";
import { renderToString }
from "react-dom/server";
import { ProductSearch }
from "./product-search";
export default async function Page() {
const serverState =
await getServerState(
<ProductSearch />,
{ renderToString }
);
return (
<ProductSearch
serverState={serverState}
/>
);
}
Dadurch sehen Suchmaschinen und Nutzer bereits gerenderte Treffer beim ersten Paint.
getServerState nutzen
getServerState rendert die Suchoberfläche serverseitig vor.
ServerState an die Client Component übergeben
Der State wird an InstantSearchSSRProvider weitergereicht.
Hydration-Fehler vermeiden
Server- und Client-State müssen identisch sein.
Warum sind Scoped API Keys wichtig?
Der Admin Key darf niemals im Browser landen.
Stattdessen erzeugen Sie pro Nutzer oder Session einen Scoped Key.
import Typesense from "typesense";
const admin = new Typesense.Client({
nodes: [
{
host: "search.example.com",
port: 443,
protocol: "https",
},
],
apiKey:
process.env.TYPESENSE_ADMIN_KEY!,
});
export async function createScopedKey(
tenantId: string
) {
return admin.keys()
.generateScopedSearchKey(
process.env
.TYPESENSE_SEARCH_ONLY_KEY!,
{
filter_by:
`tenant_id:=${tenantId}`,
expires_at:
Math.floor(Date.now() / 1000)
+ 3600,
}
);
}
Admin-Key bleibt serverseitig
Der Admin Key darf niemals öffentlich sichtbar sein.
Mandanten- und Kundengruppenfilter
Scoped Keys können Filter enthalten.
Ablaufzeit und Rechte begrenzen
Keys können zeitlich begrenzt werden.
Wie sieht ein typisches E-Commerce-Setup aus?
Eine typische Architektur:
ERP | v PIM / Middleware | v Typesense | v Next.js Storefront
Die Suche übernimmt:
- Autocomplete
- Facetten
- Filter
- Preisranges
- Sortierung
- Suchvorschläge
- semantische Suche
ERP → PIM → Typesense → Next.js
ERP liefert Stammdaten, PIM reichert an, Typesense indexiert.
B2B-Suche mit Kundengruppen und Artikelnummern
B2B-Shops benötigen häufig:
- Artikelnummernsuche
- kundenspezifische Sortimente
- Preislisten
- Rechteprüfung
Facetten, Preisranges und Sortierung
Typische Facetten:
- Marke
- Material
- Norm
- Hersteller
- Preis
Welche Probleme treten häufig auf?
Hydration Mismatch
Server- und Client-State unterscheiden sich.
CORS-Fehler
Typesense muss den Frontend-Origin erlauben.
Collection oder Feld existiert nicht
Schema und Collection stimmen nicht überein.
Versionskonflikte zwischen Adapter und InstantSearch
Major-Versionen müssen kompatibel sein.
Performance-Tipps für produktive Suche
Debouncing
Autocomplete sollte 50–150 ms debounced werden.
Minimum Query Length
Autocomplete erst ab 2–3 Zeichen starten.
Edge-Caching
Top-Queries via CDN cachen.
Facetten bewusst begrenzen
Jede Facette erhöht RAM-Verbrauch.
FAQ
Brauche ich react-instantsearch für Typesense mit Next.js?
Nein, technisch reicht das Typesense SDK. Für produktive Suchoberflächen mit SearchBox, Facetten, Pagination, URL-Sync und SSR ist react-instantsearch mit dem typesense-instantsearch-adapter jedoch meist der schnellere und stabilere Weg.
Funktioniert Typesense mit dem Next.js App Router?
Ja. Im App Router wird die Suchoberfläche als Client Component umgesetzt. Für SSR kann getServerState aus react-instantsearch genutzt werden.
Darf der Typesense Admin-Key im Frontend verwendet werden?
Nein. Der Admin-Key darf niemals im Browser landen. Für Frontends sollten Search-Only-Keys oder Scoped API Keys verwendet werden.
Was ist ein Scoped API Key?
Ein Scoped API Key ist ein eingeschränkter Suchschlüssel. Er kann Filter, Ablaufzeiten und Berechtigungen enthalten, zum Beispiel für Mandanten oder Kundengruppen.
Wie verhindere ich Hydration-Fehler?
Server- und Client-Render müssen dieselbe Adapter-Konfiguration, denselben Index-Namen und dieselben initialen Suchparameter verwenden.
Kann ich mehrere Typesense Collections in einer UI durchsuchen?
Ja. Mit dem <Index>-Widget von react-instantsearch lassen sich mehrere Collections beziehungsweise Indizes parallel durchsuchen.
Ist Typesense für B2B-E-Commerce mit Next.js geeignet?
Ja. Besonders bei Headless-Commerce-Setups mit großen Katalogen, Artikelnummernsuche, Facetten, kundenspezifischen Sortimenten und schnellen Autocomplete-Anfragen ist Typesense gut geeignet.
Brauche ich für Typesense mit Next.js einen Proxy?
Nicht zwingend. Für öffentliche Shops kann der Browser direkt mit einem Search-Only-Key suchen. Für B2B-Portale mit Login, Mandantenlogik oder komplexen Rechten ist ein Proxy über Next.js Route Handler meist besser.