Configure Deepgram multi-environment setup for dev, staging, and production. Use when setting up environment-specific configurations, managing multiple Deepgram projects, or implementing environment isolation. Trigger: "deepgram environments", "deepgram staging", "deepgram dev prod", "multi-environment deepgram", "deepgram config management".
67
82%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Configure isolated Deepgram environments for development, staging, and production. Each environment uses a separate Deepgram project, scoped API keys, environment-specific model selection, and validated configuration. Includes typed config, client factory, Docker Compose profiles, and Kubernetes overlays.
| Setting | Development | Staging | Production |
|---|---|---|---|
| Model | base (fast, cheap) | nova-3 | nova-3 |
| Concurrency | 5 | 20 | 100 |
| Diarization | Off | On | On |
| PII Redaction | Off | On | On |
| Callback URL | localhost:3000 | staging.example.com | api.example.com |
| Key Rotation | Manual | Monthly | 90-day auto |
interface DeepgramEnvConfig {
apiKey: string;
projectId: string;
model: 'base' | 'nova-2' | 'nova-3';
maxConcurrency: number;
features: {
diarize: boolean;
smart_format: boolean;
redact: string[] | false;
summarize: boolean;
};
callbackBaseUrl?: string;
timeout: number;
}
function loadConfig(env: string): DeepgramEnvConfig {
const configs: Record<string, DeepgramEnvConfig> = {
development: {
apiKey: process.env.DEEPGRAM_API_KEY_DEV!,
projectId: process.env.DEEPGRAM_PROJECT_ID_DEV!,
model: 'base',
maxConcurrency: 5,
features: {
diarize: false,
smart_format: true,
redact: false,
summarize: false,
},
callbackBaseUrl: 'http://localhost:3000',
timeout: 60000,
},
staging: {
apiKey: process.env.DEEPGRAM_API_KEY_STAGING!,
projectId: process.env.DEEPGRAM_PROJECT_ID_STAGING!,
model: 'nova-3',
maxConcurrency: 20,
features: {
diarize: true,
smart_format: true,
redact: ['pci', 'ssn'],
summarize: true,
},
callbackBaseUrl: 'https://staging.example.com',
timeout: 30000,
},
production: {
apiKey: process.env.DEEPGRAM_API_KEY_PRODUCTION!,
projectId: process.env.DEEPGRAM_PROJECT_ID_PRODUCTION!,
model: 'nova-3',
maxConcurrency: 100,
features: {
diarize: true,
smart_format: true,
redact: ['pci', 'ssn'],
summarize: true,
},
callbackBaseUrl: 'https://api.example.com',
timeout: 30000,
},
};
const config = configs[env];
if (!config) throw new Error(`Unknown environment: ${env}. Use: development, staging, production`);
if (!config.apiKey) throw new Error(`DEEPGRAM_API_KEY_${env.toUpperCase()} not set`);
return config;
}
const env = process.env.NODE_ENV ?? 'development';
const config = loadConfig(env);import { createClient, DeepgramClient } from '@deepgram/sdk';
class DeepgramClientFactory {
private static clients = new Map<string, DeepgramClient>();
static getClient(env?: string): DeepgramClient {
const environment = env ?? process.env.NODE_ENV ?? 'development';
if (!this.clients.has(environment)) {
const config = loadConfig(environment);
this.clients.set(environment, createClient(config.apiKey));
console.log(`Deepgram client created for: ${environment} (model: ${config.model})`);
}
return this.clients.get(environment)!;
}
// Convenience: transcribe with environment defaults
static async transcribe(url: string, overrides: Record<string, any> = {}) {
const environment = process.env.NODE_ENV ?? 'development';
const config = loadConfig(environment);
const client = this.getClient(environment);
const { result, error } = await client.listen.prerecorded.transcribeUrl(
{ url },
{
model: config.model,
smart_format: config.features.smart_format,
diarize: config.features.diarize,
redact: config.features.redact || undefined,
summarize: config.features.summarize ? 'v2' : undefined,
...overrides,
}
);
if (error) throw error;
return result;
}
// Reset for key rotation
static reset(env?: string) {
if (env) {
this.clients.delete(env);
} else {
this.clients.clear();
}
}
}# .env.development
DEEPGRAM_API_KEY_DEV=dev-key-here
DEEPGRAM_PROJECT_ID_DEV=dev-project-id
# .env.staging
DEEPGRAM_API_KEY_STAGING=staging-key-here
DEEPGRAM_PROJECT_ID_STAGING=staging-project-id
# .env.production (use secret manager, not file)
# DEEPGRAM_API_KEY_PRODUCTION=production-key-here
# DEEPGRAM_PROJECT_ID_PRODUCTION=production-project-id# docker-compose.yml
x-common: &common
build: .
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
services:
app-dev:
<<: *common
profiles: ["development"]
ports:
- "3000:3000"
environment:
- NODE_ENV=development
- DEEPGRAM_API_KEY_DEV=${DEEPGRAM_API_KEY_DEV}
- DEEPGRAM_PROJECT_ID_DEV=${DEEPGRAM_PROJECT_ID_DEV}
app-staging:
<<: *common
profiles: ["staging"]
ports:
- "3001:3000"
environment:
- NODE_ENV=staging
- DEEPGRAM_API_KEY_STAGING=${DEEPGRAM_API_KEY_STAGING}
- DEEPGRAM_PROJECT_ID_STAGING=${DEEPGRAM_PROJECT_ID_STAGING}
app-production:
<<: *common
profiles: ["production"]
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DEEPGRAM_API_KEY_PRODUCTION=${DEEPGRAM_API_KEY_PRODUCTION}
- DEEPGRAM_PROJECT_ID_PRODUCTION=${DEEPGRAM_PROJECT_ID_PRODUCTION}
deploy:
resources:
limits:
memory: 512M# Usage:
docker compose --profile development up
docker compose --profile staging up
docker compose --profile production up# k8s/base/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: deepgram-config
data:
DEEPGRAM_MODEL: "nova-3"
DEEPGRAM_SMART_FORMAT: "true"
---
# k8s/overlays/development/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
bases:
- ../../base
patchesStrategicMerge:
- configmap-patch.yaml
secretGenerator:
- name: deepgram-secrets
literals:
- api-key=dev-key-here
---
# k8s/overlays/development/configmap-patch.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: deepgram-config
data:
DEEPGRAM_MODEL: "base"
DEEPGRAM_MAX_CONCURRENCY: "5"async function validateEnvironments() {
const envs = ['development', 'staging', 'production'];
const results: Record<string, { valid: boolean; error?: string }> = {};
for (const env of envs) {
try {
const config = loadConfig(env);
const client = createClient(config.apiKey);
// Test 1: Key validity
const { error: authError } = await client.manage.getProjects();
if (authError) throw new Error(`Auth failed: ${authError.message}`);
// Test 2: Project access
const { error: projError } = await client.manage.getProject(config.projectId);
if (projError) throw new Error(`Project access failed: ${projError.message}`);
// Test 3: Transcription works
const { error: sttError } = await client.listen.prerecorded.transcribeUrl(
{ url: 'https://static.deepgram.com/examples/Bueller-Life-moves-702702706.wav' },
{ model: config.model, smart_format: true }
);
if (sttError) throw new Error(`STT failed: ${sttError.message}`);
results[env] = { valid: true };
console.log(`[PASS] ${env}`);
} catch (err: any) {
results[env] = { valid: false, error: err.message };
console.log(`[FAIL] ${env}: ${err.message}`);
}
}
const allValid = Object.values(results).every(r => r.valid);
console.log(`\nValidation: ${allValid ? 'ALL PASS' : 'FAILURES DETECTED'}`);
return results;
}| Issue | Cause | Solution |
|---|---|---|
DEEPGRAM_API_KEY_DEV not set | Missing env var | Set in .env.development |
| Wrong model in staging | Config mismatch | Check loadConfig mapping |
| Cross-env key used | Shared key | Create separate projects per environment |
| Validation fails for one env | Key expired | Rotate key for that environment |
0540a62
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.