Algolia reference architecture
π§ The right skill, one API call. AI agent skills registry with token-efficient skill resolution. 5,000+ skills from 500+ top repos.
npx -y skills add ComeOnOliver/skillshub --skill algolia-reference-architectureAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
What its author says it does
Copied from the file, not written here
Implement Algolia reference architecture: index design, multi-index strategy, data pipeline, search service layer, and frontend/backend separation. Trigger: "algolia architecture", "algolia best practices", "algolia project structure", "how to organize algolia", "algolia index design".
The file declares its own license as MIT. That is the authorβs claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
9.9 KB, ~1.9k tokens by cl100k_base, as published. Nobody here has run it
Algolia Reference Architecture
Overview
Production-ready architecture for Algolia-powered search. Covers index design, data pipeline from source to Algolia, service layer patterns, and frontend integration.
Architecture Overview
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Frontend β
β InstantSearch.js / React InstantSearch β
β Uses: liteClient (search-only key) β
β Sends: search-insights events (clicks, conversions) β
βββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββ
β Search + Events
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Algolia Cloud β
β βββββββββββ ββββββββββββββββ βββββββββββββββ β
β β Search β β Analytics β β Recommend β β
β β Engine β β + Insights β β (ML-based) β β
β βββββββββββ ββββββββββββββββ βββββββββββββββ β
βββββββββββββββββββββββββ²βββββββββββββββββββββββββββββββββββββββ
β Indexing (admin key)
β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Backend Service β
β ββββββββββββββ ββββββββββββββββ βββββββββββββββββββ β
β β Search β β Indexing β β Settings β β
β β Service β β Pipeline β β Manager β β
β ββββββββββββββ ββββββββ¬ββββββββ βββββββββββββββββββ β
β β β
β ββββββββββββββββββββββββΌβββββββββββββββββββββββββββββ β
β β Source Database β β
β β PostgreSQL / MongoDB / CMS / External API β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Project Structure
src/
βββ algolia/
β βββ client.ts # Singleton client (see algolia-sdk-patterns)
β βββ indices.ts # Index name constants + environment prefixing
β βββ settings/
β β βββ products.ts # Products index settings
β β βββ articles.ts # Articles index settings
β β βββ apply.ts # Script to apply all settings
β βββ transforms/
β βββ product.ts # DB record β Algolia record transformer
β βββ article.ts # DB record β Algolia record transformer
βββ services/
β βββ search.ts # Search service (wraps Algolia client)
β βββ indexing.ts # Indexing pipeline (DB β transform β Algolia)
βββ api/
β βββ search.ts # Search endpoint (returns Algolia results)
β βββ reindex.ts # Admin endpoint to trigger reindex
βββ jobs/
βββ sync-algolia.ts # Cron job for periodic full sync
Index Design Patterns
Pattern 1: One Index Per Entity Type
// src/algolia/indices.ts
const ENV = process.env.NODE_ENV === 'production' ? '' : `${process.env.NODE_ENV}_`;
export const INDICES = {
products: `${ENV}products`,
articles: `${ENV}articles`,
faq: `${ENV}faq`,
users: `${ENV}users`, // Internal search only (never expose to frontend)
} as const;
export type IndexName = typeof INDICES[keyof typeof INDICES];
Pattern 2: Record Transformer (Source β Algolia)
// src/algolia/transforms/product.ts
import type { Product } from '../db/types';
interface AlgoliaProduct {
objectID: string;
name: string;
description: string;
category: string;
brand: string;
price: number;
rating: number;
review_count: number;
in_stock: boolean;
image_url: string;
_tags: string[]; // Algolia convention: filterable tags
}
export function transformProduct(product: Product): AlgoliaProduct {
return {
objectID: product.id,
name: product.name,
description: product.description?.substring(0, 5000) || '', // Truncate
category: product.category.name,
brand: product.brand.name,
price: product.price / 100, // Cents β dollars
rating: product.avgRating,
review_count: product.reviewCount,
in_stock: product.inventory > 0,
image_url: product.images[0]?.url || '',
_tags: [
product.category.slug,
...(product.isFeatured ? ['featured'] : []),
...(product.isNew ? ['new-arrival'] : []),
],
};
}
Pattern 3: Settings as Code
// src/algolia/settings/products.ts
import type { IndexSettings } from 'algoliasearch';
export const productSettings: IndexSettings = {
searchableAttributes: [
'name',
'brand',
'category',
'unordered(description)',
],
attributesForFaceting: [
'searchable(brand)',
'category',
'filterOnly(price)',
'filterOnly(in_stock)',
'_tags',
],
customRanking: ['desc(review_count)', 'desc(rating)'],
attributesToRetrieve: ['name', 'brand', 'price', 'image_url', 'category', 'rating'],
attributesToHighlight: ['name', 'description'],
attributesToSnippet: ['description:30'],
unretrievableAttributes: ['_tags'],
distinct: 1,
attributeForDistinct: 'product_group_id',
replicas: [
'virtual(products_price_asc)',
'virtual(products_price_desc)',
'virtual(products_newest)',
],
};
// src/algolia/settings/apply.ts
import { getClient } from '../client';
import { INDICES } from '../indices';
import { productSettings } from './products';
async function applyAllSettings() {
const client = getClient();
await client.setSettings({ indexName: INDICES.products, indexSettings: productSettings });
console.log('All Algolia settings applied');
}
Pattern 4: Search Service Layer
// src/services/search.ts
import { getClient } from '../algolia/client';
import { INDICES } from '../algolia/indices';
import { ApiError } from 'algoliasearch';
export class SearchService {
private client = getClient();
async searchProducts(params: {
query: string;
filters?: string;
facetFilters?: string[][];
page?: number;
hitsPerPage?: number;
}) {
try {
return await this.client.searchSingleIndex({
indexName: INDICES.products,
searchParams: {
query: params.query,
filters: params.filters,
facetFilters: params.facetFilters,
page: params.page ?? 0,
hitsPerPage: params.hitsPerPage ?? 20,
facets: ['category', 'brand'],
clickAnalytics: true,
},
});
} catch (error) {
if (error instanceof ApiError && error.status === 404) {
return { hits: [], nbHits: 0, nbPages: 0, page: 0 };
}
throw error;
}
}
async federatedSearch(query: string) {
const { results } = await this.client.search({
requests: [
{ indexName: INDICES.products, query, hitsPerPage: 5 },
{ indexName: INDICES.articles, query, hitsPerPage: 3 },
{ indexName: INDICES.faq, query, hitsPerPage: 3 },
],
});
return results;
}
}
Error Handling
| Issue | Cause | Solution |
|---|---|---|
| Circular dependency | Service imports client imports service | Use lazy initialization |
| Config drift | Dashboard edits not in code | Apply settings from code in CI |
| Transform errors | DB schema change | Add validation in transformer |
| Index name typo | Hardcoded strings | Use INDICES constants |
Resources
Next Steps
For multi-environment setup, see algolia-multi-env-setup.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.