exa-multi-env-setup

Exa Multi-Environment Setup

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "exa-multi-env-setup" with this command: npx skills add jeremylongshore/claude-code-plugins-plus-skills/jeremylongshore-claude-code-plugins-plus-skills-exa-multi-env-setup

Exa Multi-Environment Setup

Overview

Exa's neural search API (api.exa.ai ) charges per search request. Multi-environment setup focuses on API key isolation, request caching to reduce costs in staging/production, and controlling numResults and text.maxCharacters per environment (higher values cost more).

Prerequisites

  • Exa API key(s) from dashboard.exa.ai

  • exa-js npm package (npm install exa-js )

  • Optional: Redis for search result caching in staging/production

Environment Strategy

Environment Key Isolation numResults Cache TTL Rate Limit

Development Shared dev key 3 (low cost) None Low

Staging Staging key 5 5 minutes Moderate

Production Prod key 5-10 per query 1 hour Full

Instructions

Step 1: Configuration Structure

// config/exa.ts import Exa from "exa-js";

type Env = "development" | "staging" | "production";

interface ExaConfig { apiKey: string; defaultNumResults: number; maxCharacters: number; // per result content length cacheEnabled: boolean; cacheTtlSeconds: number; }

const configs: Record<Env, ExaConfig> = { development: { apiKey: process.env.EXA_API_KEY!, defaultNumResults: 3, // fewer results = lower cost in dev maxCharacters: 500, # HTTP 500 Internal Server Error cacheEnabled: false, // don't bother caching in dev cacheTtlSeconds: 0, }, staging: { apiKey: process.env.EXA_API_KEY_STAGING!, defaultNumResults: 5, maxCharacters: 1000, # 1000: 1 second in ms cacheEnabled: true, cacheTtlSeconds: 300, // 5-minute cache in staging # 300: timeout: 5 minutes }, production: { apiKey: process.env.EXA_API_KEY_PROD!, defaultNumResults: 5, maxCharacters: 1000, # 1 second in ms cacheEnabled: true, cacheTtlSeconds: 3600, // 1-hour cache for repeated queries # 3600: timeout: 1 hour }, };

export function getExaConfig(): ExaConfig { const env = (process.env.NODE_ENV || "development") as Env; const config = configs[env] || configs.development; if (!config.apiKey) { throw new Error(EXA_API_KEY not set for ${env} environment); } return config; }

export function getExaClient(): Exa { return new Exa(getExaConfig().apiKey); }

Step 2: Search Service with Caching

// lib/exa-search.ts import { getExaClient, getExaConfig } from "../config/exa"; import { Redis } from "ioredis";

const redis = process.env.REDIS_URL ? new Redis(process.env.REDIS_URL) : null;

export async function search(query: string, numResults?: number) { const exa = getExaClient(); const cfg = getExaConfig(); const n = numResults ?? cfg.defaultNumResults;

// Check cache if enabled if (cfg.cacheEnabled && redis) { const cacheKey = exa:${Buffer.from(${query}:${n}).toString("base64")}; const cached = await redis.get(cacheKey); if (cached) return JSON.parse(cached);

const results = await exa.searchAndContents(query, {
  type: "neural",
  numResults: n,
  text: { maxCharacters: cfg.maxCharacters },
});

await redis.set(cacheKey, JSON.stringify(results), "EX", cfg.cacheTtlSeconds);
return results;

}

return exa.searchAndContents(query, { type: "neural", numResults: n, text: { maxCharacters: cfg.maxCharacters }, }); }

Step 3: Environment Variable Setup

.env.local (development)

EXA_API_KEY=exa-dev-abc123

GitHub Actions - Staging

EXA_API_KEY_STAGING=exa-staging-def456

GitHub Actions - Production

EXA_API_KEY_PROD=exa-prod-xyz789 REDIS_URL=redis://prod-redis:6379 # 6379: Redis port

Step 4: Health Check Per Environment

// lib/exa-health.ts export async function checkExaHealth(): Promise<{ status: string; env: string }> { try { const exa = getExaClient(); await exa.search("test connectivity", { numResults: 1 }); return { status: "healthy", env: process.env.NODE_ENV || "development" }; } catch (err: any) { return { status: "unhealthy", env: process.env.NODE_ENV || "development" }; } }

Step 5: CI/CD Configuration

.github/workflows/deploy.yml

jobs: deploy-staging: environment: staging env: EXA_API_KEY_STAGING: ${{ secrets.EXA_API_KEY_STAGING }} NODE_ENV: staging steps: - run: npm run build && npm run deploy:staging

deploy-production: environment: production env: EXA_API_KEY_PROD: ${{ secrets.EXA_API_KEY_PROD }} NODE_ENV: production steps: - run: npm run deploy:prod

Error Handling

Issue Cause Solution

401 Unauthorized

Wrong API key for environment Verify EXA_API_KEY in env vars

429 rate_limit_exceeded

Too many requests Implement caching and request queuing

High API costs in staging No caching enabled Enable Redis cache with 5-minute TTL

Empty results Query too narrow Broaden query terms for neural search

Examples

Check Active Configuration

import { getExaConfig } from "./config/exa";

const cfg = getExaConfig(); console.log(Results per query: ${cfg.defaultNumResults}); console.log(Cache enabled: ${cfg.cacheEnabled}, TTL: ${cfg.cacheTtlSeconds}s);

Resources

  • Exa API Documentation

  • Exa JavaScript SDK

  • Exa Pricing

Next Steps

For deployment configuration, see exa-deploy-integration .

Output

  • Configuration files or code changes applied to the project

  • Validation report confirming correct implementation

  • Summary of changes made and their rationale

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

backtesting-trading-strategies

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

svg-icon-generator

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

performance-lighthouse-runner

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

mindmap-generator

No summary provided by upstream source.

Repository SourceNeeds Review