Quickstarts

Next.js Search Quickstart

Getting Started With Upstash Search and Next.js


1. Create a Search Database

Follow the instructions in the Getting Started guide to create a Search Database.


2. Project Setup

Let's create a new Next.js application and install the @upstash/search package:

npx create-next-app@latest search-appcd search-appnpm install @upstash/search

3. Add Environment Variables

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

UPSTASH_SEARCH_REST_URL=<YOUR_SEARCH_REST_URL>UPSTASH_SEARCH_REST_TOKEN=<YOUR_SEARCH_REST_TOKEN>

4. Create an API Route to Upsert Documents

Create an API route in app/api/upsert/route.ts:

app/api/upsert/route.ts
import { Search } from "@upstash/search"const client = new Search({  url: process.env.UPSTASH_SEARCH_REST_URL,  token: process.env.UPSTASH_SEARCH_REST_TOKEN,})const index = client.index("my-index")export async function POST() {  await index.upsert([    {      id: "movie-1",      content: {        title: "Inception",        description: "A thriller about dreams within dreams.",      },      metadata: { genre: "sci-fi", year: 2010 },    },    {      id: "movie-2",      content: {        title: "The Godfather",        description: "A story about a powerful Italian-American crime family.",      },      metadata: { genre: "crime", year: 1972 },    },    {      id: "movie-3",      content: {        title: "The Dark Knight",        description: "A tale of Batman's fight against the Joker.",      },      metadata: { genre: "action", year: 2008 },    },  ])  return new Response("OK")}

5. Create a Route to Search Documents

Create an API route in app/api/search/route.ts:

app/api/search/route.ts
import { Search } from "@upstash/search"const client = new Search({  url: process.env.UPSTASH_SEARCH_REST_URL,  token: process.env.UPSTASH_SEARCH_REST_TOKEN,})const index = client.index("my-index")export async function POST(req: Request) {  const { query } = (await req.json()) as { query: string }  const results = await index.search({ query })  return new Response(JSON.stringify(results))}

6. Create a Simple Page

Add the following code in app/page.tsx:

app/page.tsx
"use client";import { useState } from "react";interface SearchResult {  id: string;  content: Record<string, unknown>;  metadata: Record<string, unknown>;  score: number;}export default function Home() {  const [searchResults, setSearchResults] = useState<SearchResult[]>([]);  const [query, setQuery] = useState("");  const [isUpserting, setIsUpserting] = useState(false);  const [upsertSuccess, setUpsertSuccess] = useState(false);  const upsertData = async () => {    setIsUpserting(true);    setUpsertSuccess(false);    await fetch("/api/upsert", { method: "POST" });    setIsUpserting(false);    setUpsertSuccess(true);  };  const search = async () => {    const res = await fetch(`/api/search`, {      method: "POST",      headers: { "Content-Type": "application/json" },      body: JSON.stringify({ query }),    });    const data = await res.json();    setSearchResults(data || []);  };  return (    <main className="min-h-screen bg-emerald-50 flex flex-col items-center py-10">      <div className="w-full max-w-2xl bg-white shadow-md rounded-lg p-6">        <header className="mb-6 text-center">          <h1 className="text-2xl font-bold text-emerald-800">Search App</h1>          <p className="text-emerald-600">            Upsert data and search through the database.          </p>        </header>        <div className="mb-6">          <button            onClick={upsertData}            disabled={isUpserting}            className={`w-full py-2 px-4 rounded-md text-white ${              isUpserting                ? "bg-emerald-300"                : "bg-emerald-500 hover:bg-emerald-600"            }`}          >            {isUpserting ? "Upserting..." : "Upsert Data"}          </button>          {upsertSuccess && (            <p className="mt-2 text-sm text-emerald-600">              Data upserted successfully!            </p>          )}        </div>        <div className="mb-6">          <div className="flex gap-2">            <input              type="text"              value={query}              onChange={(e) => setQuery(e.target.value)}              placeholder="Search..."              className="flex-1 border border-emerald-300 rounded-md px-4 py-2 text-gray-800 focus:outline-none focus:ring-2 focus:ring-emerald-500"            />            <button              onClick={search}              className="bg-emerald-500 text-white px-4 py-2 rounded-md hover:bg-emerald-600"            >              Search            </button>          </div>        </div>        <ul className="space-y-2">          {searchResults.map((result, index) => (            <li              key={index}              className="bg-emerald-100 p-4 rounded-md shadow-sm text-emerald-800"            >              <p className="font-bold">ID: {result.id}</p>              <p className="text-sm">Content: {JSON.stringify(result.content)}</p>              <p className="text-sm">Metadata: {JSON.stringify(result.metadata)}</p>              <p className="text-sm">Score: {result.score}</p>            </li>          ))}        </ul>      </div>    </main>  );}

7. 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 click the Upsert Data button to add three movies to your database and use the search bar to make a query.


Next Steps

Learn more about:

Loading search…