To add full-text search to Firebase, sync your Firestore data to Algolia using a Cloud Function that triggers on document writes. Each time a document is created, updated, or deleted, the function mirrors the change in an Algolia index. On the client side, use Algolia's InstantSearch library for real-time search UI with facets, highlighting, and typo tolerance that Firestore cannot provide natively.
Adding Full-Text Search to Firebase with Algolia
Firestore does not support full-text search natively. The standard solution is to sync Firestore data to a dedicated search service like Algolia, which provides typo tolerance, faceted filtering, and sub-50ms query times. This tutorial shows you how to create Firestore triggers that keep an Algolia index in sync and how to build a search interface using Algolia's InstantSearch React library.
Prerequisites
- A Firebase project on the Blaze plan (required for Cloud Functions and outbound network calls)
- An Algolia account with an application ID and Admin API Key (free tier available)
- Cloud Functions initialized in your project (firebase init functions)
- Node.js 18+ installed
Step-by-step guide
Install Algolia SDK in your functions directory
Install Algolia SDK in your functions directory
Navigate to your functions directory and install the Algolia search client. This package runs server-side inside Cloud Functions. You will use the Admin API key to write to the Algolia index, so it must never be exposed to the client.
1cd functions2npm install algoliasearchExpected result: algoliasearch is added to functions/package.json dependencies.
Store Algolia credentials as secrets
Store Algolia credentials as secrets
Use Firebase's defineSecret to store your Algolia Application ID and Admin API Key in Cloud Secret Manager. This avoids hardcoding sensitive values and makes them available to your Cloud Functions at runtime.
1// functions/src/index.ts2import { defineSecret } from 'firebase-functions/params'34const ALGOLIA_APP_ID = defineSecret('ALGOLIA_APP_ID')5const ALGOLIA_ADMIN_KEY = defineSecret('ALGOLIA_ADMIN_KEY')67// Set the secrets:8// firebase functions:secrets:set ALGOLIA_APP_ID9// firebase functions:secrets:set ALGOLIA_ADMIN_KEYExpected result: Secrets are stored in Cloud Secret Manager and accessible in your function code.
Create a Firestore trigger to sync data to Algolia
Create a Firestore trigger to sync data to Algolia
Write a Cloud Function v2 that fires on document writes in your target collection. On create and update events, the function saves the document data plus its Firestore ID as the Algolia objectID. On delete, it removes the record from the index. The function must declare the secrets it needs in its options.
1// functions/src/index.ts2import { onDocumentWritten } from 'firebase-functions/v2/firestore'3import algoliasearch from 'algoliasearch'45const ALGOLIA_APP_ID = defineSecret('ALGOLIA_APP_ID')6const ALGOLIA_ADMIN_KEY = defineSecret('ALGOLIA_ADMIN_KEY')7const ALGOLIA_INDEX_NAME = 'products'89export const syncToAlgolia = onDocumentWritten(10 {11 document: 'products/{productId}',12 secrets: [ALGOLIA_APP_ID, ALGOLIA_ADMIN_KEY]13 },14 async (event) => {15 const client = algoliasearch(16 ALGOLIA_APP_ID.value(),17 ALGOLIA_ADMIN_KEY.value()18 )19 const index = client.initIndex(ALGOLIA_INDEX_NAME)20 const { productId } = event.params2122 // Document was deleted23 if (!event.data?.after.exists) {24 await index.deleteObject(productId)25 return26 }2728 // Document was created or updated29 const data = event.data.after.data()30 await index.saveObject({31 objectID: productId,32 ...data33 })34 }35)Expected result: Every Firestore write to the products collection is mirrored to the Algolia index.
Configure Algolia index settings
Configure Algolia index settings
Set searchable attributes and ranking criteria in the Algolia dashboard or programmatically. This tells Algolia which fields to search and how to rank results. Configure this once; the settings persist across all future indexing operations.
1// One-time setup script (run locally)2import algoliasearch from 'algoliasearch'34const client = algoliasearch('YOUR_APP_ID', 'YOUR_ADMIN_KEY')5const index = client.initIndex('products')67await index.setSettings({8 searchableAttributes: ['name', 'description', 'category'],9 attributesForFaceting: ['category', 'price'],10 customRanking: ['desc(createdAt)']11})Expected result: Algolia searches the name, description, and category fields and supports faceted filtering on category and price.
Build the search UI with InstantSearch
Build the search UI with InstantSearch
Install Algolia's InstantSearch library for your frontend framework and create a search component. Use the Search-Only API Key (not the Admin key) for client-side queries. InstantSearch provides pre-built widgets for search boxes, hit lists, facet filters, and pagination.
1npm install algoliasearch react-instantsearch23// src/components/Search.tsx4import algoliasearch from 'algoliasearch/lite'5import { InstantSearch, SearchBox, Hits, Highlight } from 'react-instantsearch'67const searchClient = algoliasearch(8 import.meta.env.VITE_ALGOLIA_APP_ID,9 import.meta.env.VITE_ALGOLIA_SEARCH_KEY10)1112function Hit({ hit }: { hit: any }) {13 return (14 <div>15 <h3><Highlight attribute="name" hit={hit} /></h3>16 <p>{hit.description}</p>17 </div>18 )19}2021export function Search() {22 return (23 <InstantSearch searchClient={searchClient} indexName="products">24 <SearchBox placeholder="Search products..." />25 <Hits hitComponent={Hit} />26 </InstantSearch>27 )28}Expected result: A search box appears that queries Algolia in real-time and displays matching products with highlighted terms.
Deploy and test the sync function
Deploy and test the sync function
Deploy your Cloud Function and create a test document in Firestore. Check the Algolia dashboard to verify the document appears in the index. Then update and delete the document to confirm the sync function handles all write types correctly.
1firebase deploy --only functions:syncToAlgoliaExpected result: The function deploys successfully. Creating a document in the products collection triggers indexing in Algolia within seconds.
Complete working example
1// functions/src/index.ts2import { onDocumentWritten } from 'firebase-functions/v2/firestore'3import { defineSecret } from 'firebase-functions/params'4import algoliasearch from 'algoliasearch'56const ALGOLIA_APP_ID = defineSecret('ALGOLIA_APP_ID')7const ALGOLIA_ADMIN_KEY = defineSecret('ALGOLIA_ADMIN_KEY')8const ALGOLIA_INDEX_NAME = 'products'910export const syncToAlgolia = onDocumentWritten(11 {12 document: 'products/{productId}',13 secrets: [ALGOLIA_APP_ID, ALGOLIA_ADMIN_KEY]14 },15 async (event) => {16 const client = algoliasearch(17 ALGOLIA_APP_ID.value(),18 ALGOLIA_ADMIN_KEY.value()19 )20 const index = client.initIndex(ALGOLIA_INDEX_NAME)21 const { productId } = event.params2223 // Handle deletion24 if (!event.data?.after.exists) {25 await index.deleteObject(productId)26 console.log(`Deleted ${productId} from Algolia`)27 return28 }2930 // Handle create or update31 const data = event.data.after.data()32 await index.saveObject({33 objectID: productId,34 name: data?.name,35 description: data?.description,36 category: data?.category,37 price: data?.price,38 createdAt: data?.createdAt?.toMillis() ?? Date.now()39 })40 console.log(`Synced ${productId} to Algolia`)41 }42)Common mistakes when using Firebase with Algolia for Full-Text Search
Why it's a problem: Using the Algolia Admin API Key on the client side, which gives anyone full write and delete access to your index
How to avoid: Use the Search-Only API Key for client-side queries. The Admin key must only be used in Cloud Functions or other server-side code.
Why it's a problem: Forgetting to set objectID when saving to Algolia, causing Algolia to generate random IDs that cannot be matched to Firestore documents
How to avoid: Always set objectID to the Firestore document ID. This allows update and delete operations to target the correct Algolia record.
Why it's a problem: Not handling the delete case in the onDocumentWritten trigger, leaving orphaned records in the Algolia index
How to avoid: Check if event.data.after.exists is false. If the document was deleted, call index.deleteObject with the document ID to remove it from Algolia.
Why it's a problem: Syncing all document fields to Algolia including sensitive data like user emails or internal IDs
How to avoid: Explicitly select which fields to index by destructuring only the fields you want. Never sync entire documents blindly with the spread operator in production.
Best practices
- Store Algolia Admin API Key in Cloud Secret Manager using defineSecret, never in .env files or source code
- Use the algoliasearch/lite bundle on the client for a smaller bundle size
- Set searchableAttributes in Algolia to control which fields are searched and in what priority order
- Include the Firestore document ID as the Algolia objectID to maintain a 1:1 mapping for updates and deletes
- For initial backfill of existing data, write a one-time script that reads all Firestore documents and batch-indexes them to Algolia
- If your project involves complex search requirements across multiple collections, RapidDev can help architect the sync pipeline and search infrastructure
- Monitor Algolia usage in the dashboard to stay within your plan's record and operation limits
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I have a Firestore collection called 'articles' with fields title, body, and tags. Show me how to write a Cloud Function v2 that syncs this collection to Algolia on every create, update, and delete. Also show the client-side search component using react-instantsearch.
Create a Firebase Cloud Function that syncs my 'products' Firestore collection to an Algolia search index. Use onDocumentWritten triggers with v2 syntax, store the Algolia credentials with defineSecret, and handle creates, updates, and deletes. Include the Algolia index configuration for searchable attributes.
Frequently asked questions
Is there a Firebase Extension for Algolia?
Yes. The 'Search with Algolia' extension automates the sync between Firestore and Algolia without writing custom Cloud Functions. Install it from the Firebase Extensions Hub and configure the collection path, fields to sync, and Algolia credentials.
How much does Algolia cost for Firebase projects?
Algolia offers a free tier with 10,000 search requests per month and 10,000 records. The paid plans start at $1 per 1,000 search requests. For most Firebase projects in early stages, the free tier is sufficient.
Can I use Typesense instead of Algolia?
Yes. Typesense is an open-source alternative you can self-host. The sync pattern is identical: create a Cloud Function trigger that writes to the Typesense API on Firestore document changes. Typesense also has a Firebase Extension.
How do I backfill existing Firestore data to Algolia?
Write a one-time Node.js script that reads all documents from your Firestore collection using the Admin SDK and batch-indexes them to Algolia using index.saveObjects(). After the backfill, the Cloud Function trigger handles ongoing syncs.
Will the sync function slow down my Firestore writes?
No. Firestore triggers are asynchronous. The write to Firestore completes immediately and the Cloud Function runs in the background. Users do not experience any latency from the Algolia sync.
How do I handle partial updates without overwriting the entire Algolia record?
Use index.partialUpdateObject() instead of saveObject() if you only want to update specific fields. However, for most use cases, saving the full object on each update is simpler and ensures consistency.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation