algolia-local-dev-loop

Installation
SKILL.md

Algolia Local Dev Loop

Overview

Set up a fast, reproducible local development workflow for Algolia. Use separate dev indices, mock the client in tests, and iterate without touching production data.

Prerequisites

  • Completed algolia-install-auth setup
  • Node.js 18+ with npm/pnpm
  • Vitest or Jest for testing

Instructions

Step 1: Environment-Based Index Names

// src/algolia/config.ts
import { algoliasearch } from 'algoliasearch';

const ENV = process.env.NODE_ENV || 'development';

// Each environment gets its own index prefix
export function indexName(base: string): string {
  if (ENV === 'production') return base;
  return `${ENV}_${base}`; // e.g., "development_products"
}

export const client = algoliasearch(
  process.env.ALGOLIA_APP_ID!,
  process.env.ALGOLIA_ADMIN_KEY!
);

Step 2: Seed Script for Dev Data

// scripts/seed-algolia.ts
import { client, indexName } from '../src/algolia/config';

const SEED_DATA = [
  { objectID: 'prod-1', name: 'Widget A', category: 'tools', price: 29.99 },
  { objectID: 'prod-2', name: 'Widget B', category: 'tools', price: 49.99 },
  { objectID: 'prod-3', name: 'Gadget C', category: 'electronics', price: 199.99 },
];

async function seed() {
  const idx = indexName('products');

  // replaceAllObjects atomically swaps index content
  const { taskID } = await client.replaceAllObjects({
    indexName: idx,
    objects: SEED_DATA,
  });
  await client.waitForTask({ indexName: idx, taskID });

  // Configure settings for the dev index
  await client.setSettings({
    indexName: idx,
    indexSettings: {
      searchableAttributes: ['name', 'category'],
      attributesForFaceting: ['category', 'filterOnly(price)'],
      customRanking: ['asc(price)'],
    },
  });

  console.log(`Seeded ${SEED_DATA.length} records into ${idx}`);
}

seed().catch(console.error);
{
  "scripts": {
    "seed:algolia": "npx tsx scripts/seed-algolia.ts",
    "dev": "tsx watch src/index.ts",
    "test": "vitest",
    "test:watch": "vitest --watch"
  }
}

Step 3: Mock Algolia in Unit Tests

// tests/algolia.test.ts
import { describe, it, expect, vi, beforeEach } from 'vitest';

// Mock the entire algoliasearch module
vi.mock('algoliasearch', () => ({
  algoliasearch: vi.fn(() => ({
    searchSingleIndex: vi.fn().mockResolvedValue({
      hits: [
        { objectID: '1', name: 'Widget A', _highlightResult: {} },
      ],
      nbHits: 1,
      page: 0,
      nbPages: 1,
    }),
    saveObjects: vi.fn().mockResolvedValue({ taskID: 123 }),
    waitForTask: vi.fn().mockResolvedValue({}),
  })),
}));

import { algoliasearch } from 'algoliasearch';

describe('Product Search', () => {
  const client = algoliasearch('test-app-id', 'test-api-key');

  it('returns matching products', async () => {
    const { hits } = await client.searchSingleIndex({
      indexName: 'development_products',
      searchParams: { query: 'widget' },
    });
    expect(hits).toHaveLength(1);
    expect(hits[0].name).toBe('Widget A');
  });
});

Step 4: Integration Test with Real API

// tests/integration/algolia.integration.test.ts
import { describe, it, expect } from 'vitest';
import { algoliasearch } from 'algoliasearch';

describe.skipIf(!process.env.ALGOLIA_APP_ID)('Algolia Integration', () => {
  const client = algoliasearch(
    process.env.ALGOLIA_APP_ID!,
    process.env.ALGOLIA_ADMIN_KEY!
  );
  const testIndex = `test_${Date.now()}_products`;

  it('indexes and searches records', async () => {
    // Index
    const { taskID } = await client.saveObjects({
      indexName: testIndex,
      objects: [{ objectID: '1', name: 'Test Product' }],
    });
    await client.waitForTask({ indexName: testIndex, taskID });

    // Search
    const { hits } = await client.searchSingleIndex({
      indexName: testIndex,
      searchParams: { query: 'test' },
    });
    expect(hits.length).toBeGreaterThan(0);

    // Cleanup
    await client.deleteIndex({ indexName: testIndex });
  });
});

Error Handling

Error Cause Solution
Index does not exist Dev index not seeded Run npm run seed:algolia
Test pollution Shared index between tests Use unique timestamped index names
Stale search results Indexing not waited Always await client.waitForTask() after writes
Mock not applied Wrong import order Ensure vi.mock() is before imports

Examples

Clean Dev Index on Start

// scripts/reset-dev-algolia.ts
import { client, indexName } from '../src/algolia/config';

async function reset() {
  const idx = indexName('products');
  try {
    await client.deleteIndex({ indexName: idx });
    console.log(`Deleted ${idx}`);
  } catch (e) {
    // Index may not exist yet — that's fine
  }
}

reset().catch(console.error);

Resources

Next Steps

See algolia-sdk-patterns for production-ready code patterns.

Weekly Installs
1
GitHub Stars
2.1K
First Seen
Apr 13, 2026