ElevenLabs Local Dev Loop
Overview
Set up a fast, cost-effective local development workflow for ElevenLabs audio
projects. The loop centers on three moves — mock the SDK so unit tests never
burn character quota, gate real API calls behind an explicit
ELEVENLABS_INTEGRATION=1 flag, and select a cheaper model in dev while keeping
the high-quality model for production — with tsx watch hot reload and a quota
checker to round out the cycle.
Follow the high-level flow below to scaffold the project, then drill into references/implementation.md for the full code of every step and references/examples.md for worked end-to-end runs.
Prerequisites
Before starting, confirm your environment is ready:
- The
elevenlabs-install-authsetup is complete, so the SDK (@elevenlabs/elevenlabs-js) is installed andELEVENLABS_API_KEYis available in.env.local. - Node.js 18+ with
npmorpnpm. vitestinstalled as the test runner (recommended) — it powers the mock layer and the integration-test guard.
Instructions
Work through the six steps in order. Each is summarized here; the full code for every step lives in references/implementation.md.
-
Project structure — lay out
src/elevenlabs/(client, config, tts),tests/__mocks__/andtests/fixtures/sample.mp3, a git-ignoredoutput/, and.env.local/.env.example. Full tree in the reference. -
Environment configuration — write an environment-aware
config.tsthat picks the model and output format byNODE_ENV. This is the essential skeleton:// src/elevenlabs/config.ts export function loadConfig() { const env = process.env.NODE_ENV || "development"; return { apiKey: process.env.ELEVENLABS_API_KEY || "", // cheaper/faster in dev, best quality in prod modelId: env === "production" ? "eleven_multilingual_v2" // 1.0 credits/char : "eleven_flash_v2_5", // 0.5 credits/char, ~75ms defaultVoiceId: process.env.ELEVENLABS_VOICE_ID || "21m00Tcm4TlvDq8ikWAM", outputFormat: "mp3_22050_32", // smaller files for dev }; } -
Mock the SDK — write
tests/__mocks__/elevenlabs.tsthat returns thesample.mp3fixture fromtextToSpeech.convert/streamand stubsvoices.getAllanduser.get, so unit tests cost nothing. -
Development scripts — add
dev(tsx watch),test,test:watch,test:integration,generate, andquotascripts topackage.json. -
Quota-aware development — add
src/check-quota.tsthat readsuser.subscriptionand exits non-zero when fewer than 1000 characters remain, so a low balance fails fast. -
Integration test guard — write
tests/tts.test.tswhere the real-API test isit.skipIf(!useRealApi)and only runs underELEVENLABS_INTEGRATION=1; the mocked test always runs.
See references/implementation.md for the complete, copy-pasteable code for each step.
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 |
|-------|-------|----------|
| MODULE_NOT_FOUND | 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 ELEVENLABS_API_KEY in .env.local |
| Quota exceeded in dev | Running real API calls | Use mock layer; run npm run quota first |
Examples
Four worked runs of the loop — full walkthroughs in references/examples.md:
- Zero-cost unit tests —
npm run testdrives the service through the mock client, passes offline, and never touches the API or your quota. - Quota preflight —
npm run quotaprintsCharacters: 500 / 10,000 (5.0% used)and exits1when fewer than 1000 characters remain, blocking a paid run before it starts. - Opt-in integration run —
npm run test:integrationsetsELEVENLABS_INTEGRATION=1, flipping theit.skipIf(!useRealApi)test on so the real API is hit only when you ask for it. - Hot-reload iteration —
npm run dev(tsx watch) restarts on save; with the dev model (eleven_flash_v2_5) and mocks, each loop stays fast and free.
Resources
Next Steps
Once the dev loop is running, move on to production-ready code: see the
elevenlabs-sdk-patterns skill for streaming, retries, and voice-management
patterns you can layer on top of this environment.