Algolia cost tuning
Skill ComeOnOliver/skillshub/skills/jeremylongshore/claude-code-plugins-plus-skills/algolia-cost-tuning
🧠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-cost-tuningAssembled 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
Optimize Algolia costs: understand search request vs record pricing, reduce operations with batching and caching, monitor usage via Analytics API. Trigger: "algolia cost", "algolia billing", "reduce algolia costs", "algolia pricing", "algolia expensive", "algolia budget".
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
6.9 KB, as published. Nobody here has run it
Algolia Cost Tuning
Overview
Algolia pricing is based on search requests and records. A search request is one API call (which may contain multiple queries via search({ requests: [...] })). Records are counted across all indices including replicas.
Pricing Structure (2025)
| Plan | Records Included | Search Requests | Additional Cost |
|---|---|---|---|
| Build (Free) | 1M records | 10K requests/mo | N/A |
| Grow | 100K free, then $0.40/1K | 10K free, then $0.50/1K | Pay as you go |
| Grow Plus | 100K free, then $0.40/1K | 10K free, then $1.75/1K | + AI features |
| Premium | Custom | Custom | Volume discounts |
What Counts as Records
- Every object in every index = 1 record
- Standard replicas duplicate records (multiply your count)
- Virtual replicas share records (no extra cost)
- Synonyms and rules do NOT count as records
What Counts as Search Requests
searchSingleIndex()= 1 requestsearch({ requests: [q1, q2, q3] })= 1 request (multi-query)browse()= 1 request per pagesaveObjects()= NOT a search request (indexing operations are free)
Instructions
Step 1: Audit Current Usage
import { algoliasearch } from 'algoliasearch';
const client = algoliasearch(process.env.ALGOLIA_APP_ID!, process.env.ALGOLIA_ADMIN_KEY!);
// Check total records across all indices
const { items } = await client.listIndices();
let totalRecords = 0;
let replicaRecords = 0;
items.forEach(idx => {
const records = idx.entries || 0;
console.log(`${idx.name}: ${records.toLocaleString()} records, ${(idx.dataSize || 0 / 1024).toFixed(0)}KB`);
if (idx.name.includes('_replica') || idx.primary) {
replicaRecords += records;
}
totalRecords += records;
});
console.log(`\nTotal: ${totalRecords.toLocaleString()} records (${replicaRecords.toLocaleString()} in replicas)`);
Step 2: Replace Standard Replicas with Virtual Replicas
// Standard replicas: duplicate all records (doubles cost)
// Virtual replicas: share records with primary (no extra cost)
// BEFORE: 3 standard replicas = 4x record count
await client.setSettings({
indexName: 'products',
indexSettings: {
replicas: [
// 'products_price_asc', // Standard: costs records
// 'products_price_desc', // Standard: costs records
'virtual(products_price_asc)', // Virtual: FREE
'virtual(products_price_desc)', // Virtual: FREE
],
},
});
// Virtual replica limitation: can only customize ranking and customRanking
// If you need different searchableAttributes or attributesForFaceting, use standard
Step 3: Use Multi-Query to Reduce Request Count
// BAD: 3 separate requests = 3 search operations billed
const results1 = await client.searchSingleIndex({ indexName: 'products', searchParams: { query: 'laptop' } });
const results2 = await client.searchSingleIndex({ indexName: 'articles', searchParams: { query: 'laptop' } });
const results3 = await client.searchSingleIndex({ indexName: 'faq', searchParams: { query: 'laptop' } });
// GOOD: 1 multi-query request = 1 search operation billed
const { results } = await client.search({
requests: [
{ indexName: 'products', query: 'laptop', hitsPerPage: 5 },
{ indexName: 'articles', query: 'laptop', hitsPerPage: 3 },
{ indexName: 'faq', query: 'laptop', hitsPerPage: 3 },
],
});
Step 4: Cache Frequent Searches
import { LRUCache } from 'lru-cache';
// Cache popular searches — Algolia's own CDN caches are limited
const searchCache = new LRUCache<string, any>({
max: 1000,
ttl: 5 * 60 * 1000, // 5 minutes for product search
});
async function cachedSearch(query: string, filters?: string) {
const key = JSON.stringify({ query, filters });
const cached = searchCache.get(key);
if (cached) {
console.log('Cache hit — saved 1 search request');
return cached;
}
const result = await client.searchSingleIndex({
indexName: 'products',
searchParams: { query, filters },
});
searchCache.set(key, result);
return result;
}
Step 5: Delete Unused Indices
// Audit and clean up test/development indices
const { items } = await client.listIndices();
const devIndices = items.filter(i =>
i.name.startsWith('test_') ||
i.name.startsWith('dev_') ||
i.name.startsWith('ci_')
);
for (const idx of devIndices) {
console.log(`Deleting unused index: ${idx.name} (${idx.entries} records)`);
await client.deleteIndex({ indexName: idx.name });
}
Step 6: Monitor Usage with Analytics API
// Track search volume trends
const { count: searchCount } = await client.getSearchesCount({
index: 'products',
startDate: '2025-01-01',
endDate: '2025-01-31',
});
console.log(`Search requests this month: ${searchCount.toLocaleString()}`);
// Identify no-result queries (wasted searches users will retry)
const { searches } = await client.getSearchesNoResults({
index: 'products',
startDate: '2025-01-01',
endDate: '2025-01-31',
});
console.log('Top no-result searches (fix these to reduce retries):');
searches.slice(0, 10).forEach(s => console.log(` "${s.search}" — ${s.count} times`));
Cost Reduction Summary
| Strategy | Savings | Effort |
|---|---|---|
| Virtual replicas | 50-75% record cost | Low |
| Multi-query search | 60-80% fewer requests | Low |
| Client-side caching | 30-50% fewer requests | Low |
| Delete unused indices | Variable | Low |
| Fix no-result queries (synonyms) | 10-20% fewer retries | Medium |
| Reduce record size | Indirect (faster = cheaper) | Medium |
Error Handling
| Issue | Cause | Solution |
|---|---|---|
| Unexpected bill spike | Uncached bot traffic | Add rate limiting, cache layer |
| Record count higher than expected | Standard replicas | Switch to virtual replicas |
| Search requests over budget | No caching | Add LRU cache in API layer |
| Analytics API returns empty | Wrong date range or region | Check region parameter matches your app |
Resources
Next Steps
For architecture patterns, see algolia-reference-architecture.