- Published on
Drupal faceted search with Typesense and InstantSearch
- Authors
- Name
- Christophe Jossart
- @colorfield
In this post, we will show how to setup a decoupled Algolia InstantSearch implementation with a Typesense backend and Drupal Search API.
Typesense is an open source alternative to Algolia, the first difference that I noticed is the pricing model:
- Per infra resource and not per query
- Possibilty to use Cloud or on premise
So I started to evaluate it quickly on my local with the homebrew package and it's blazing fast!
It's written in C++
and stores in the memory. The main difference with Drupal facets is that Drupal / Views is fully skipped, the query is done straight on the server.
I was looking for an alternative to Drupal facets for several reasons
- A project we are working on will be fully decoupled soon and I wanted to incrementally decouple by soft decoupling faceted search that were built with views
- We had a performance issue on high traffic sites, as ajax updates facets blocks with
POST
requests, which caused issues with CDN cacheability - Our Solr setup is quite complex
- Some ajax cases were not working out for us without patches, that we need to maintain when updating
Typesense appeared to be a very good candidate and it can also be extended for semantic search / RAG with the AI module. When talking with others at the Moutain Camp, Meilisearch was also mentioned as a nice alternative. The focus of this post is Typesense though, so we will continue with the latter.
Fortunately the heavy lifting was already done
- For the backend server integration, there is a Drupal module that integrates with Search API, Luca gave a great session about that at Drupal Mountain Camp 2025, that inspired this post
- For the frontend UI, there are several options, but using Algolia InstantSearch widgets is possible with the Typesense adapter
- Algolia widgets are available in vanilla JS, for React, Vue, ... so it is quite portable
The frontend example below will use React, but it can be easily ported to your favourite stack.
Step by step configuration
Install and start Typesense server
We will use macOS here
brew install typesense/tap/typesense-server@28.0
brew services start typesense-server@28.0
For other infra, follow this documentation Local Machine / Self-Hosting
The default API key is xyz
Install Drupal with Search API Typesense
For our example, we will use what Drupal has out of the box: the Article
content type and the Tags
vocabulary.
- Articles will be Algolia InstantSearch
Hits
- Tags will be the Facet items, in our example we will use the
RefinementList
# Install Drupal and Drush
composer create-project drupal/recommended-project drupal-typesense
cd drupal-typesense
php web/core/scripts/drupal install standard
composer require drush/drush
## Generate some tags and articles
composer require drupal/devel
drush en devel_generate
drush gent 10 --bundles=tags --max-depth=1
drush genc --bundles=article
# Install Typesense
composer require 'drupal/search_api_typesense:^1.0'
drush en search_api_typesense
Create the Search API server
- Head to
/admin/config/search/search-api
- Add the Server
- Name:
Typesense
- Admin API Key:
xyz
- Host:
localhost
- Port:
8108
- Protocol:
http
- Name:
- With the API Keys tab, create a readonly one
- Description:
Search articles
- Actions: tick
documents:search
- Collections:
articles
(that matches the index machine name)
- Description:
- Copy the API Key for later
Create the index
- Head back to
/admin/config/search/search-api
- Add the index
- Name:
Articles
- Datasources:
Content
- Content datasource:
Only those selected
and selectArticle
- Server:
Typesense
- Click on
Save and add fields
- Expand
field_tags
and addfield_tags:entity:name
- Add
title
- Click on
Done
- Name:
Configure fields
- Change the machine name
name
for the Tags totags
and selectTypesense: string[]
for the type - Select
Typesense: string
for the title - Click on
Save changes
Configure Typesense schema
- Use the
Schema
tab, so/admin/config/search/search-api/index/articles/schema
- For tags, tick
Facet
andOptional
- Click on
Save
- Click on
Index now
Configure processors
You might most likely want to enable at least Content access
and/or Entity status
.
You are all set for the Drupal part.
For more details, follow instructions from the maintainers.
Create the React UI
We will use Vite React / SWC / Typescript template with PNPM, but feel free to use anything else.
pnpm create vite facets --template react-swc-ts
cd facets
Add Algolia packages
pnpm add instantsearch.js
pnpm add react-instantsearch
Add Typesense adapter
pnpm add typesense-instantsearch-adapter
Minimal application
In App.tsx
, replace the boilerplate inner code in the App
function, your file should look like this
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter({
server: {
// Be sure to use the search-only-api-key.
// Use env variables.
apiKey: 'READ_ONLY_API_KEY',
nodes: [
{
host: 'localhost',
port: 8108,
protocol: 'http',
},
],
},
additionalSearchParameters: {
query_by: 'title',
},
})
const { searchClient } = typesenseInstantsearchAdapter
const indexName = 'articles'
return (
<div>
<header className="header">
<h1 className="header-title">
<a href="/">React InstantSearch with Typesense</a>
</h1>
using Drupal Search API
</header>
<div className="container">
<InstantSearch searchClient={searchClient} indexName={indexName} routing={true}>
<Configure hitsPerPage={10} />
<div className="search-panel">
<div className="search-panel__filters">
<FacetPanel header="Tags">
<RefinementList attribute="tags" sortBy={['name:asc']} />
</FacetPanel>
</div>
<div className="search-panel__results">
<SearchBox placeholder="" className="searchbox" />
<Hits hitComponent={Hit} />
<div className="pagination">
<Pagination />
</div>
</div>
</div>
</InstantSearch>
</div>
</div>
)
The complete example for the frontend is available in this repository, just make sure to replace the api key by the read-only one set earlier.
What's next?
You can then embed this as a React island with a Drupal library, for soft decoupling, or use it in your fully decoupled project.
In another post, I will elaborate some of the findings that I had to solve, for the frontend to be production ready, like:
- handle multilingual facets
- filter content by language
- write a custom processor for language fallback
- sort facet items by term weight
- use path alias
- use radio widgets
- use an empty state
- host the Typesense server with Docker
- ...