Skillshub algolia-deploy-integration
install
source · Clone the upstream repo
git clone https://github.com/ComeOnOliver/skillshub
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/ComeOnOliver/skillshub "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/jeremylongshore/claude-code-plugins-plus-skills/algolia-deploy-integration" ~/.claude/skills/comeonoliver-skillshub-algolia-deploy-integration && rm -rf "$T"
manifest:
skills/jeremylongshore/claude-code-plugins-plus-skills/algolia-deploy-integration/SKILL.mdsource content
Algolia Deploy Integration
Overview
Deploy Algolia-powered applications to production platforms with proper API key separation (Admin on backend, Search-Only on frontend) and InstantSearch widget integration.
Prerequisites
- Algolia App ID + Admin key (backend) + Search-Only key (frontend)
- Platform CLI installed (vercel, fly, or gcloud)
v5 for backend,algoliasearch
orreact-instantsearch
for frontendinstantsearch.js
Instructions
Step 1: Backend API Key Configuration
Vercel
# 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.io
fly secrets set \ ALGOLIA_APP_ID=YourApplicationID \ ALGOLIA_ADMIN_KEY=your_admin_key \ ALGOLIA_SEARCH_KEY=your_search_key
Google Cloud Run
# 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
Step 2: Backend Search API (Next.js API Route)
// 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 }); }
Step 3: Frontend with InstantSearch (React)
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> ); }
Step 4: Frontend with Vanilla InstantSearch.js
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();
Step 5: Health Check Endpoint
// 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 }); } }
Error Handling
| Issue | Cause | Solution |
|---|---|---|
var undefined | Not set in Vercel env | Add with |
| InstantSearch shows no results | Wrong Search-Only key | Verify key ACL includes |
| Backend write fails on Vercel | Using search key for indexing | Use (non-public) |
| Cold start timeout | Large client init | Use lite client where possible |
Resources
Next Steps
For event tracking and analytics, see
algolia-webhooks-events.