From algolia-pack
Deploys Algolia-powered apps to Vercel, Fly.io, and Cloud Run with secure API key management and InstantSearch frontend integration.
npx claudepluginhub jeremylongshore/claude-code-plugins-plus-skills --plugin algolia-packThis skill is limited to using the following tools:
Deploy Algolia-powered applications to production platforms with proper API key separation (Admin on backend, Search-Only on frontend) and InstantSearch widget integration.
Installs Algolia JavaScript v5 client, configures API keys via env vars, and initializes backend/frontend clients in Node.js/TypeScript projects.
Provides patterns for Algolia search implementation using React InstantSearch hooks, indexing strategies, relevance tuning, and Next.js SSR integration.
Provides expert patterns for Algolia search implementation, indexing strategies, React InstantSearch, relevance tuning, autocomplete, typeahead, and faceted search.
Share bugs, ideas, or general feedback.
Deploy Algolia-powered applications to production platforms with proper API key separation (Admin on backend, Search-Only on frontend) and InstantSearch widget integration.
algoliasearch v5 for backend, react-instantsearch or instantsearch.js for frontend# Environment variables in Vercel
vercel env add ALGOLIA_APP_ID production # Your Application ID
vercel env add ALGOLIA_ADMIN_KEY production # Admin key (server-side only)
vercel env add ALGOLIA_SEARCH_KEY production # Search-only key (can be public)
# For client-side access (Next.js convention)
vercel env add NEXT_PUBLIC_ALGOLIA_APP_ID production
vercel env add NEXT_PUBLIC_ALGOLIA_SEARCH_KEY production
fly secrets set \
ALGOLIA_APP_ID=YourApplicationID \
ALGOLIA_ADMIN_KEY=your_admin_key \
ALGOLIA_SEARCH_KEY=your_search_key
# Store in Secret Manager
echo -n "your_admin_key" | gcloud secrets create algolia-admin-key --data-file=-
echo -n "your_search_key" | gcloud secrets create algolia-search-key --data-file=-
# Deploy with secrets mounted as env vars
gcloud run deploy search-service \
--image gcr.io/$PROJECT_ID/search-service \
--set-secrets=ALGOLIA_ADMIN_KEY=algolia-admin-key:latest,ALGOLIA_SEARCH_KEY=algolia-search-key:latest \
--region us-central1
// app/api/search/route.ts
import { algoliasearch } from 'algoliasearch';
import { NextRequest, NextResponse } from 'next/server';
const client = algoliasearch(
process.env.ALGOLIA_APP_ID!,
process.env.ALGOLIA_ADMIN_KEY!
);
export async function GET(request: NextRequest) {
const query = request.nextUrl.searchParams.get('q') || '';
const page = parseInt(request.nextUrl.searchParams.get('page') || '0');
const { hits, nbHits, nbPages } = await client.searchSingleIndex({
indexName: 'products',
searchParams: {
query,
hitsPerPage: 20,
page,
attributesToRetrieve: ['name', 'price', 'image_url', 'category'],
attributesToHighlight: ['name'],
},
});
return NextResponse.json({ hits, totalHits: nbHits, totalPages: nbPages, page });
}
npm install react-instantsearch algoliasearch
// components/AlgoliaSearch.tsx
import { liteClient } from 'algoliasearch/lite';
import {
InstantSearch,
SearchBox,
Hits,
RefinementList,
Pagination,
Highlight,
} from 'react-instantsearch';
const searchClient = liteClient(
process.env.NEXT_PUBLIC_ALGOLIA_APP_ID!,
process.env.NEXT_PUBLIC_ALGOLIA_SEARCH_KEY!
);
function Hit({ hit }: { hit: any }) {
return (
<article>
<h3><Highlight attribute="name" hit={hit} /></h3>
<p>${hit.price}</p>
<p>{hit.category}</p>
</article>
);
}
export default function AlgoliaSearch() {
return (
<InstantSearch searchClient={searchClient} indexName="products">
<SearchBox placeholder="Search products..." />
<div style={{ display: 'flex', gap: '2rem' }}>
<aside>
<h4>Category</h4>
<RefinementList attribute="category" />
<h4>Brand</h4>
<RefinementList attribute="brand" searchable />
</aside>
<main>
<Hits hitComponent={Hit} />
<Pagination />
</main>
</div>
</InstantSearch>
);
}
npm install instantsearch.js algoliasearch
import instantsearch from 'instantsearch.js';
import { searchBox, hits, refinementList, pagination } from 'instantsearch.js/es/widgets';
import { liteClient } from 'algoliasearch/lite';
const searchClient = liteClient('YourAppID', 'YourSearchOnlyKey');
const search = instantsearch({
indexName: 'products',
searchClient,
});
search.addWidgets([
searchBox({ container: '#searchbox' }),
hits({
container: '#hits',
templates: {
item: (hit, { html, components }) => html`
<article>
<h3>${components.Highlight({ hit, attribute: 'name' })}</h3>
<p>$${hit.price}</p>
</article>
`,
},
}),
refinementList({ container: '#category-filter', attribute: 'category' }),
pagination({ container: '#pagination' }),
]);
search.start();
// app/api/health/route.ts
import { algoliasearch } from 'algoliasearch';
const client = algoliasearch(process.env.ALGOLIA_APP_ID!, process.env.ALGOLIA_ADMIN_KEY!);
export async function GET() {
const start = Date.now();
try {
const { items } = await client.listIndices();
return Response.json({
status: 'healthy',
algolia: {
connected: true,
latencyMs: Date.now() - start,
indexCount: items.length,
},
});
} catch (error) {
return Response.json({
status: 'degraded',
algolia: { connected: false, error: String(error) },
}, { status: 503 });
}
}
| Issue | Cause | Solution |
|---|---|---|
NEXT_PUBLIC_ var undefined | Not set in Vercel env | Add with vercel env add |
| InstantSearch shows no results | Wrong Search-Only key | Verify key ACL includes search |
| Backend write fails on Vercel | Using search key for indexing | Use ALGOLIA_ADMIN_KEY (non-public) |
| Cold start timeout | Large client init | Use lite client where possible |
For event tracking and analytics, see algolia-webhooks-events.