elevenlabs-local-dev-loop

'Configure local ElevenLabs development with mocking, hot reload, and

6 Tools
elevenlabs-pack Plugin
saas packs Category

Allowed Tools

ReadWriteEditBash(npm:*)Bash(pnpm:*)Grep

Provided by Plugin

elevenlabs-pack

Claude Code skill pack for ElevenLabs (18 skills)

saas packs v1.0.0
View Plugin

Installation

This skill is included in the elevenlabs-pack plugin:

/plugin install elevenlabs-pack@claude-code-plugins-plus

Click to copy

Instructions

ElevenLabs Local Dev Loop

Overview

Set up a fast, cost-effective local development workflow for ElevenLabs audio projects. Includes SDK mocking to avoid burning character quota during development, audio output testing, and hot-reload patterns.

Prerequisites

  • Completed elevenlabs-install-auth setup
  • Node.js 18+ with npm/pnpm
  • vitest for testing (recommended)

Instructions

Step 1: Project Structure


my-elevenlabs-project/
├── src/
│   ├── elevenlabs/
│   │   ├── client.ts       # Singleton client wrapper
│   │   ├── config.ts       # Environment-aware config
│   │   └── tts.ts          # TTS service layer
│   └── index.ts
├── tests/
│   ├── __mocks__/
│   │   └── elevenlabs.ts   # SDK mock for free testing
│   ├── tts.test.ts
│   └── fixtures/
│       └── sample.mp3      # Known-good audio for comparison
├── output/                  # Generated audio (git-ignored)
├── .env.local               # Local API key (git-ignored)
├── .env.example             # Template for team
└── package.json

Step 2: Environment Configuration


// src/elevenlabs/config.ts
export interface ElevenLabsConfig {
  apiKey: string;
  modelId: string;
  defaultVoiceId: string;
  outputFormat: string;
}

export function loadConfig(): ElevenLabsConfig {
  const env = process.env.NODE_ENV || "development";

  return {
    apiKey: process.env.ELEVENLABS_API_KEY || "",
    // Use cheaper/faster model in dev, high-quality in prod
    modelId: env === "production"
      ? "eleven_multilingual_v2"    // 1.0 credits/char, best quality
      : "eleven_flash_v2_5",       // 0.5 credits/char, ~75ms latency
    defaultVoiceId: process.env.ELEVENLABS_VOICE_ID || "21m00Tcm4TlvDq8ikWAM",
    outputFormat: "mp3_22050_32",  // Smaller files for dev
  };
}

Step 3: Mock the SDK for Unit Tests


// tests/__mocks__/elevenlabs.ts
// Avoids API calls (and character charges) during testing
import { vi } from "vitest";
import { readFileSync } from "fs";

const sampleAudio = readFileSync("tests/fixtures/sample.mp3");

export const mockElevenLabsClient = {
  textToSpeech: {
    convert: vi.fn().mockResolvedValue(
      new ReadableStream({
        start(controller) {
          controller.enqueue(sampleAudio);
          controller.close();
        },
      })
    ),
    stream: vi.fn().mockImplementation(async function* () {
      yield sampleAudio.subarray(0, 1024);
      yield sampleAudio.subarray(1024);
    }),
  },
  voices: {
    getAll: vi.fn().mockResolvedValue({
      voices: [
        { voice_id: "21m00Tcm4TlvDq8ikWAM", name: "Rachel" },
        { voice_id: "ErXwobaYiN019PkySvjV", name: "Antoni" },
      ],
    }),
  },
  user: {
    get: vi.fn().mockResolvedValue({
      subscription: {
        tier: "free",
        character_count: 500,
        character_limit: 10000,
      },
    }),
  },
};

Step 4: Development Scripts


{
  "scripts": {
    "dev": "tsx watch src/index.ts",
    "test": "vitest",
    "test:watch": "vitest --watch",
    "test:integration": "ELEVENLABS_INTEGRATION=1 vitest run tests/integration/",
    "generate": "tsx src/generate.ts",
    "quota": "tsx src/check-quota.ts"
  }
}

Step 5: Quota-Aware Development


// src/check-quota.ts — run before integration tests
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";

const client = new ElevenLabsClient();

async function checkQuota() {
  const user = await client.user.get();
  const { character_count, character_limit } = user.subscription;
  const remaining = character_limit - character_count;
  const pct = ((character_count / character_limit) * 100).toFixed(1);

  console.log(`Characters: ${character_count.toLocaleString()} / ${character_limit.toLocaleString()} (${pct}% used)`);
  console.log(`Remaining: ${remaining.toLocaleString()} characters`);

  if (remaining < 1000) {
    console.warn("WARNING: Low character quota. Use mocks for development.");
    process.exit(1);
  }
}

checkQuota().catch(console.error);

Step 6: Integration Test Guard


// tests/tts.test.ts
import { describe, it, expect, vi, beforeAll } from "vitest";
import { mockElevenLabsClient } from "./__mocks__/elevenlabs";

// Only hit real API when explicitly enabled
const useRealApi = process.env.ELEVENLABS_INTEGRATION === "1";

describe("TTS Service", () => {
  it("should generate audio from text (mocked)", async () => {
    const audio = await mockElevenLabsClient.textToSpeech.convert(
      "21m00Tcm4TlvDq8ikWAM",
      { text: "Test speech", model_id: "eleven_flash_v2_5" }
    );
    expect(audio).toBeDefined();
  });

  it.skipIf(!useRealApi)("should generate real audio (integration)", async () => {
    const { ElevenLabsClient } = await import("@elevenlabs/elevenlabs-js");
    const client = new ElevenLabsClient();
    const audio = await client.textToSpeech.convert("21m00Tcm4TlvDq8ikWAM", {
      text: "Integration test.",
      model_id: "eleven_flash_v2_5",
    });
    expect(audio).toBeDefined();
  });
});

Output

  • Working development environment with hot reload via tsx watch
  • Mock layer that avoids API calls and character charges during dev
  • Quota checker to prevent surprise billing
  • Integration test guard pattern (ELEVENLABS_INTEGRATION=1)
  • Environment-aware model selection (cheap in dev, quality in prod)

Error Handling

Error Cause Solution
MODULENOTFOUND SDK not installed npm install @elevenlabs/elevenlabs-js
Mock returns undefined Mock not wired Check vi.mock path matches import
Integration test fails No API key Set ELEVENLABSAPIKEY in .env.local
Quota exceeded in dev Running real API calls Use mock layer; run npm run quota first

Resources

Next Steps

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

Ready to use elevenlabs-pack?