How to Add Full-Text Search to a Next.js App in 10 Minutes
April 15, 2026
Most Next.js apps start with basic filtering or client-side string matching. That works until your data grows beyond a few hundred items. At that point you need real full-text search with relevance ranking. Here's how to add it with LumoSearch in about 10 minutes.
What you'll build
A search-as-you-type interface that queries a LumoSearch collection and displays results with highlighted matching text. The search runs client-side using a public API key — no server-side proxy needed.
Step 1: Prepare your data
LumoSearch accepts JSON arrays. Each object becomes a searchable document. Decide which fields should be searchable and what weights they should have.
// articles.json
[
{
"id": "1",
"title": "Getting Started with Next.js",
"body": "Next.js is a React framework...",
"tags": ["react", "nextjs", "tutorial"]
},
// ... more articles
]Step 2: Create a collection
Create a project and collection via the API or dashboard. Specify searchable fields with weights:
// Field configuration
{
"title": { "weight": 3 },
"body": { "weight": 1 },
"tags": { "weight": 2 }
}Titles are weighted 3x because a title match is a strong relevance signal. Tags at 2x because they're curated keywords. Body at 1x as the baseline.
Step 3: Upload your documents
Use the admin API key to upload your JSON array. LumoSearch indexes it asynchronously — for most datasets under 10K documents, indexing completes in seconds.
const response = await fetch(
`${API_URL}/v1/collections/${collectionId}/documents:replace`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${adminKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(articles),
}
);Step 4: Install the SDK
npm install @lumosearch/cloud
Step 5: Build the search component
'use client';
import { useState } from 'react';
import { LumoCloud } from '@lumosearch/cloud';
const client = new LumoCloud({
apiKey: process.env.NEXT_PUBLIC_LUMO_SEARCH_KEY,
host: process.env.NEXT_PUBLIC_LUMO_API_URL,
});
export function SearchBar() {
const [query, setQuery] = useState('');
const [results, setResults] = useState([]);
async function handleSearch(value: string) {
setQuery(value);
if (value.length < 2) {
setResults([]);
return;
}
const res = await client.search('your-collection-id', value, {
limit: 5,
attributesToHighlight: ['title', 'body'],
});
setResults(res.hits);
}
return (
<div>
<input
type="text"
value={query}
onChange={(e) => handleSearch(e.target.value)}
placeholder="Search articles..."
/>
<ul>
{results.map((hit) => (
<li key={hit.id}>
<strong>{hit.title}</strong>
</li>
))}
</ul>
</div>
);
}Step 6: Deploy
The public search key is safe to expose in client-side code — it can only perform search and autocomplete on the scoped collection. Deploy your Next.js app as usual.
Next steps
- Add debouncing to reduce API calls while typing
- Use the autocomplete endpoint for faster prefix suggestions
- Display highlight ranges to show matching snippets
- Re-index on content changes via a webhook or CI step
Get started with LumoSearch
The open-source engine runs locally for development. When you're ready for production, LumoSearch Cloud handles hosting and scaling. View pricing.