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-auth setup is complete, so the SDK
(@elevenlabs/elevenlabs-js) is installed and ELEVENLABS_API_KEY is
available in .env.local.
- Node.js 18+ with
npm or pnpm.
vitest installed 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__/ and tests/fixtures/sample.mp3, a git-ignored output/,
and .env.local / .env.example. Full tree in the reference.
Environment configuration — write an environment-aware config.ts that
picks the model and output format by NODE_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.ts that returns the
sample.mp3 fixture from textToSpeech.convert/stream and stubs
voices.getAll and user.get, so unit tests cost nothing.
Development scripts — add dev (tsx watch), test, test:watch,
test:integration, generate, and quota scripts to package.json.
Quota-aware development — add src/check-quota.ts that reads
user.subscription and exits non-zero when fewer than 1000 characters
remain, so a low balance fails fast.
Integration test guard — write tests/tts.test.ts where the real-API
test is it.skipIf(!useRealApi) and only runs under
ELEVENLABS_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 test drives the service through the mock
client, passes offline, and never touches the API or your quota.
- Quota preflight —
npm run quota prints Characters: 500 / 10,000 (5.0% used) and exits 1 when fewer than 1000 characters remain, blocking a paid
run before it starts.
- Opt-in integration run —
npm run test:integration sets
ELEVENLABS_INTEGRATION=1, flipping the it.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.
Source: jeremylongshore/claude-code-plugins-plus-skills → skills/.curated/elevenlabs-local-dev-loop/SKILL.md
Also appears in: jeremylongshore/claude-code-plugins-plus-skills/plugins/saas-packs/elevenlabs-pack/skills/elevenlabs-local-dev-loop/SKILL.md
1---2name: elevenlabs-local-dev-loop3description: | Use when setting up a local ElevenLabs dev environment for a TTS/voice project and you need SDK mocking, hot reload, quota-aware iteration, and audio-output testing that does not burn character quota during development. Trigger with "elevenlabs dev setup", "elevenlabs local development", "elevenlabs dev environment", "develop with elevenlabs", "test elevenlabs locally".4---56# ElevenLabs Local Dev Loop78## Overview910Set up a fast, cost-effective local development workflow for ElevenLabs audio11projects. The loop centers on three moves — mock the SDK so unit tests never12burn character quota, gate real API calls behind an explicit13`ELEVENLABS_INTEGRATION=1` flag, and select a cheaper model in dev while keeping14the high-quality model for production — with `tsx watch` hot reload and a quota15checker to round out the cycle.1617Follow the high-level flow below to scaffold the project, then drill into18[references/implementation.md](references/implementation.md) for the full code19of every step and [references/examples.md](references/examples.md) for worked20end-to-end runs.2122## Prerequisites2324Before starting, confirm your environment is ready:2526- The `elevenlabs-install-auth` setup is complete, so the SDK27 (`@elevenlabs/elevenlabs-js`) is installed and `ELEVENLABS_API_KEY` is28 available in `.env.local`.29- Node.js 18+ with `npm` or `pnpm`.30- `vitest` installed as the test runner (recommended) — it powers the mock31 layer and the integration-test guard.3233## Instructions3435Work through the six steps in order. Each is summarized here; the full code for36every step lives in [references/implementation.md](references/implementation.md).37381. **Project structure** — lay out `src/elevenlabs/` (client, config, tts),39 `tests/__mocks__/` and `tests/fixtures/sample.mp3`, a git-ignored `output/`,40 and `.env.local` / `.env.example`. Full tree in the reference.412. **Environment configuration** — write an environment-aware `config.ts` that42 picks the model and output format by `NODE_ENV`. This is the essential43 skeleton:4445 ```typescript46 // src/elevenlabs/config.ts47 export function loadConfig() {48 const env = process.env.NODE_ENV || "development";49 return {50 apiKey: process.env.ELEVENLABS_API_KEY || "",51 // cheaper/faster in dev, best quality in prod52 modelId: env === "production"53 ? "eleven_multilingual_v2" // 1.0 credits/char54 : "eleven_flash_v2_5", // 0.5 credits/char, ~75ms55 defaultVoiceId: process.env.ELEVENLABS_VOICE_ID || "21m00Tcm4TlvDq8ikWAM",56 outputFormat: "mp3_22050_32", // smaller files for dev57 };58 }59 ```60613. **Mock the SDK** — write `tests/__mocks__/elevenlabs.ts` that returns the62 `sample.mp3` fixture from `textToSpeech.convert`/`stream` and stubs63 `voices.getAll` and `user.get`, so unit tests cost nothing.644. **Development scripts** — add `dev` (`tsx watch`), `test`, `test:watch`,65 `test:integration`, `generate`, and `quota` scripts to `package.json`.665. **Quota-aware development** — add `src/check-quota.ts` that reads67 `user.subscription` and exits non-zero when fewer than 1000 characters68 remain, so a low balance fails fast.696. **Integration test guard** — write `tests/tts.test.ts` where the real-API70 test is `it.skipIf(!useRealApi)` and only runs under71 `ELEVENLABS_INTEGRATION=1`; the mocked test always runs.7273See [references/implementation.md](references/implementation.md) for the74complete, copy-pasteable code for each step.7576## Output7778- Working development environment with hot reload via `tsx watch`79- Mock layer that avoids API calls and character charges during dev80- Quota checker to prevent surprise billing81- Integration test guard pattern (`ELEVENLABS_INTEGRATION=1`)82- Environment-aware model selection (cheap in dev, quality in prod)8384## Error Handling8586| Error | Cause | Solution |87|-------|-------|----------|88| `MODULE_NOT_FOUND` | SDK not installed | `npm install @elevenlabs/elevenlabs-js` |89| Mock returns undefined | Mock not wired | Check vi.mock path matches import |90| Integration test fails | No API key | Set `ELEVENLABS_API_KEY` in `.env.local` |91| Quota exceeded in dev | Running real API calls | Use mock layer; run `npm run quota` first |9293## Examples9495Four worked runs of the loop — full walkthroughs in96[references/examples.md](references/examples.md):9798- **Zero-cost unit tests** — `npm run test` drives the service through the mock99 client, passes offline, and never touches the API or your quota.100- **Quota preflight** — `npm run quota` prints `Characters: 500 / 10,000 (5.0%101 used)` and exits `1` when fewer than 1000 characters remain, blocking a paid102 run before it starts.103- **Opt-in integration run** — `npm run test:integration` sets104 `ELEVENLABS_INTEGRATION=1`, flipping the `it.skipIf(!useRealApi)` test on so105 the real API is hit only when you ask for it.106- **Hot-reload iteration** — `npm run dev` (`tsx watch`) restarts on save; with107 the dev model (`eleven_flash_v2_5`) and mocks, each loop stays fast and free.108109## Resources110111- [ElevenLabs JS SDK](https://github.com/elevenlabs/elevenlabs-js)112- [Vitest Mocking](https://vitest.dev/guide/mocking.html)113- [tsx (TypeScript Execute)](https://github.com/privatenumber/tsx)114115## Next Steps116117Once the dev loop is running, move on to production-ready code: see the118`elevenlabs-sdk-patterns` skill for streaming, retries, and voice-management119patterns you can layer on top of this environment.120121---122123**Source:** [`jeremylongshore/claude-code-plugins-plus-skills`](https://github.com/jeremylongshore/claude-code-plugins-plus-skills) → `skills/.curated/elevenlabs-local-dev-loop/SKILL.md`124125**Also appears in:** `jeremylongshore/claude-code-plugins-plus-skills/plugins/saas-packs/elevenlabs-pack/skills/elevenlabs-local-dev-loop/SKILL.md`