DEV Community

Cover image for Building a Search bar for your Gatsby site with Typesense
Jason Bosco
Jason Bosco

Posted on • Originally published at Medium

Building a Search bar for your Gatsby site with Typesense

🤔 Context

Gatsby currently has two options for adding a search bar to your site:

  1. Using a Javascript-based search library like Lunr / ElasticLunr
  2. Using a proprietary Search-as-A-Service like Algolia

😞 The Problem

While a JS-based search library works great for small sites with limited content, for large Gatsby sites, it ends up bloating your bundle size because the entire search index needs to be bundled with your site’s assets. This large bundle needs to be downloaded to your visitors’ browser which unfortunately increases your site’s page load times.

Algolia works great for documentation sites, since Algolia offers a free DocSearch service. However for Gatsby sites with a large amount of traffic or content or both, Algolia can become expensive quickly. It is also a proprietary solution and the Gatsby plugin for Algolia is currently in beta and not officially supported.

✨ The Solution

Enter Typesense, an open source search engine that is simple to use, run and scale, with clean APIs and documentation. Think of it as an open source alternative to Algolia and an easier-to-use, batteries-included alternative to ElasticSearch.

Read more about Typesense’s out-of-the-box features here.

The Gatsby-Typesense plugin helps you to index data from your Gatsby site to a Typesense Search cluster and then quickly build a powerful instant search interface using InstantSearch.js.

The cool thing about this plugin is that it works for both static and dynamic Gatsby sites. It does not depend on you using Markdown, React or any particular plugin. It scans the output of your Gatsby public folder for HTML files and directly indexes content from the markup.

How to add Search to a Gatsby site

The rest of this article will walk you through how you can add an Instant Search bar to your Gatsby site with Typesense.

I’m going to assume that you already have a working Gatsby site. If not, here is a good place to learn how to.

👣 Step 1: Install the Typesense plugin for Gatsby

From your Gatsby site’s root:

npm install gatsby-plugin-typesense @babel/runtime
Enter fullscreen mode Exit fullscreen mode

👣 Step 2: Start a Typesense server

The simplest way to run a Typesense server is using Docker:

mkdir /tmp/typesense-server-data

docker run -i -p 8108:8108 -v/tmp/typesense-server-data/:/data typesense/typesense:0.15.0 --data-dir /data --api-key=xyz --listen-port 8108 --enable-cors
Enter fullscreen mode Exit fullscreen mode

You can also download native binaries from the downloads page.

If you’d prefer a hosted version of Typesense, you can also spin up a cluster on Typesense Cloud.

👣 Step 3: Configure the Plugin

In your gatsby-config.js file, configure the gatsby-plugin-typesense plugin:

// gatsby-config.js

module.exports = {
  plugins: [
    {
      resolve: `gatsby-plugin-typesense`,
      options: {
        publicDir: `${__dirname}/public`, // Required
        collectionSchema: { // Required
          name: "pages_v1",
          fields: [
            {
              name: "title",
              type: "string",
            },
            {
              name: "description",
              type: "string",
            },
            {
              name: "tags",
              type: "string[]",
              optional: true,
              facet: true,
            },
            {
              name: "page_path", // Required
              type: "string",
            },
            {
              name: "page_priority_score", // Required
              type: "int32",
            },
          ],
          default_sorting_field: "page_priority_score", // Required
        },
        server: { // Required
          apiKey: "xyz",
          nodes: [
            {
              host: "localhost",
              port: "8108",
              protocol: "http",
            },
          ],
        },
      },
    },
  ],
}
Enter fullscreen mode Exit fullscreen mode

To learn more about what the different configuration options mean, read this section of the plugin's documentation.

👣 Step 4: Markup your content

Add a data attribute called data-typesense-field to any HTML elements that contain the data you want to be indexed for that page.

For example, if you have the following HTML snippet in a file:

<!-- ./public/about/index.html -->

...

<h1 data-typesense-field="title">About Us</h1>
<p data-typesense-field="description">
  Hello, we are Stark Industries.
</p>
<div>
  <span data-typesense-field="tags">about</span>
  <span data-typesense-field="tags">misc</span>
</div>

...
Enter fullscreen mode Exit fullscreen mode

When you build your site, the plugin will index this page as the following structured document in Typesense:

{
  "title": "About Us",
  "description": "Hello, we are Stark Industries.",
  "tags": ["about", "misc"],
  "page_path": "/about/",
  "page_priority_score": 10
}
Enter fullscreen mode Exit fullscreen mode

You can also add any arbitrary fields to the document, by adding the data-typesense-field data attribute to any HTML element and adding the corresponding field to the schema under the plugin’s configuration options.

Now, you want to run gatsby build and the plugin will automatically be triggered post-build and it will index the content you’ve marked up into Typesense 🎉

👣 Step 5: Build your Search UI

The good folks over at Algolia have built and open-sourced Instantsearch.js which is a powerful collection of out-of-the-box UI components that you can use to compose interactive search experiences quickly.

Typesense has an integration with InstantSearch.js (and its React cousin), that lets you use a Typesense cluster with InstantSearch.js UI components:

https://github.com/typesense/typesense-instantsearch-adapter

First, install the react-instantsearch and the adapter:

npm install typesense-instantsearch-adapter react-instantsearch-dom @babel/runtime
Enter fullscreen mode Exit fullscreen mode

Here’s a quick minimal example of a search interface using react-instantsearch:

import { InstantSearch, SearchBox, Hits, Stats } from "react-instantsearch-dom"
import TypesenseInstantSearchAdapter from "typesense-instantsearch-adapter"
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter({
  server: {
    apiKey: "xyz", // Be sure to use the search-only-api-key
    nodes: [
      {
        host: "localhost",
        port: "8108",
        protocol: "http",
      },
    ],
  },
  // The following parameters are directly passed to Typesense's search API endpoint.
  //  So you can pass any parameters supported by the search endpoint below.
  //  queryBy is required.
  additionalSearchParameters: {
    queryBy: "title,description,tags",
  },
})
const searchClient = typesenseInstantsearchAdapter.searchClient
export default function SearchInterface() {
  const Hit = ({ hit }) => (
    <p>
      {hit.title} - {hit.description}
    </p>
  )
return (
      <InstantSearch searchClient={searchClient} indexName="pages_v1">
        <SearchBox />
        <Stats />
        <Hits hitComponent={Hit} />
      </InstantSearch>
  )
}
Enter fullscreen mode Exit fullscreen mode

InstantSearch.js supports a variety of additional search widgets. Read more about how to use them in their documentation here.

🔥 And that’s it! 🚀

You now have a working search bar, with Instant Search, typo tolerance and more, powered by Typesense and InstantSearch.js.

Please let me know if you run into any issues in the comments.

Top comments (0)