Introduction

Upstash Search makes it easy to add a fast, ready-to-use search bar to your docs site, no complex setup needed. In this tutorial, you’ll learn how to quickly integrate a modern search experience that helps your users find what they need. With just a few tweaks, you can use this solution in any project and deliver great search lightning fast.


1. Project Setup

First, create an Upstash Search Database if you don’t already have one (Getting Started guide) and then create a new Next.js application and install the related packages:

npx create-next-app@latest search-docs-app
cd search-docs-app
npm install @upstash/search @upstash/search-ui lucide-react

2. Add Environment Variables

Find the environment variables from your database dashboard and add them to your .env file:

NEXT_PUBLIC_UPSTASH_SEARCH_URL=<YOUR_SEARCH_REST_URL>
NEXT_PUBLIC_UPSTASH_READONLY_TOKEN=<YOUR_SEARCH_READONLY_TOKEN>

3. Create the Component

Create the search component in app/components/search-bar.tsx:

app/components/search-bar.tsx
"use client"

import { SearchBar } from "@upstash/search-ui"
import "@upstash/search-ui/dist/index.css"
import { Search } from "@upstash/search"
import { FileText } from "lucide-react"

const client = new Search({
  url: process.env.NEXT_PUBLIC_UPSTASH_SEARCH_URL! ,
  token: process.env.NEXT_PUBLIC_UPSTASH_SEARCH_READONLY_TOKEN!,
})
// 👇 your search index name
const index = client.index<{ title: string }>("default")

export default function SearchComponent() {
  return (
    <div className="max-w-sm mt-24 mx-auto">
      <SearchBar.Dialog>
        <SearchBar.DialogTrigger placeholder="Search..." />

        <SearchBar.DialogContent>
          <SearchBar.Input placeholder="Type to search..." />
          <SearchBar.Results
            searchFn={(query) => {
              // 👇 100% type-safe: whatever you return here is
              // automatically typed as `result` below
              return index.search({ query, limit: 10, reranking: true })
            }}
          >
            {(result) => (
                <div key={result.id} onClick={() => {
                   window.open(result.metadata?.url as string, "_blank")
                 }}>
               <SearchBar.Result 
                 value={result.id} 
                 className="cursor-pointer hover:bg-gray-50 transition-colors duration-200"
               >
                <SearchBar.ResultIcon>
                    <FileText className="text-gray-600" />
                </SearchBar.ResultIcon>

                <SearchBar.ResultContent>
                  <SearchBar.ResultTitle>
                    {result.content.title}
                  </SearchBar.ResultTitle>
                  <p className="text-xs text-gray-500 mt-0.5">Docs</p>
                </SearchBar.ResultContent>
              </SearchBar.Result>
              </div>
            )}
          </SearchBar.Results>
        </SearchBar.DialogContent>
      </SearchBar.Dialog>
    </div>
  )
}

4. Crawl Docs to Feed the Component

Call npx @upstash/search-crawler in your command line and follow the CLI, you will be prompted to provide:

  • Upstash Search URL (as set in your environment variables)
  • Upstash Search Rest Token (as set in your environment variables)
  • Upstash Search Index Name (Go for default for convenience)
  • Docs URL to crawl (Let’s go for https://upstash.com/docs)

If you prefer not to choose default index name, don’t forget to update the line in the SearchComponent where you provide the index name.


5. Prepare the UI

Replace the following code snippet with the code in app/page.tsx:

app/page.tsx
import SearchComponent from "./components/search-bar";

export default function Home() {
  return (
    <div className="min-h-screen bg-gradient-to-br from-blue-50 via-white to-indigo-50">
      <main className="flex-1">
        <div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 pt-20 pb-16">
          <div className="text-center mb-12">
            <h2 className="text-4xl md:text-5xl font-bold text-gray-900 mb-6">
              Search Upstash Documentation
            </h2>
            <p className="text-xl text-gray-600 max-w-2xl mx-auto leading-relaxed">
              Find exactly what you're looking for in our comprehensive documentation.
              Search through guides, APIs, tutorials, and more with lightning-fast results.
            </p>
          </div>
          {/* Search Component */}
          <div className="max-w-2xl mx-auto">
            <SearchComponent />
          </div>
          <div className="mt-20 grid md:grid-cols-3 gap-8">
            <div className="text-center">
              <div className="w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center mx-auto mb-4">
                <svg className="w-6 h-6 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2}
                    d="M13 10V3L4 14h7v7l9-11h-7z" />
                </svg>
              </div>
              <h3 className="text-lg font-semibold text-gray-900 mb-2">Lightning Fast</h3>
              <p className="text-gray-600">Get instant search results powered by advanced indexing</p>
            </div>
            <div className="text-center">
              <div className="w-12 h-12 bg-green-100 rounded-lg flex items-center justify-center mx-auto mb-4">
                <svg className="w-6 h-6 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2}
                    d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
                </svg>
              </div>
              <h3 className="text-lg font-semibold text-gray-900 mb-2">Accurate Results</h3>
              <p className="text-gray-600">Reranking ensures the most relevant content appears first</p>
            </div>
            <div className="text-center">
              <div className="w-12 h-12 bg-purple-100 rounded-lg flex items-center justify-center mx-auto mb-4">
                <svg className="w-6 h-6 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2}
                    d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 
                  18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 
                  5c1.746 0 3.332.477 4.5 1.253v13C19.832 18.477 18.246 18 16.5 18c-1.746 
                  0-3.332.477-4.5 1.253" />
                </svg>
              </div>
              <h3 className="text-lg font-semibold text-gray-900 mb-2">Comprehensive</h3>
              <p className="text-gray-600">Search across all documentation, guides, and API references</p>
            </div>
          </div>
        </div>
      </main>
    </div>
  );
}



6. Start the Project

Run the following command to start the development server:

npm run dev

Open your browser and navigate to http://localhost:3000 to test the application.

You can search through Upstash docs, and results will redirect you to the page you are looking for.


Next Steps

Learn more about: