Skip to content
Back to skills

Exa Multi Env Setup

ASecurity

Configure Exa neural search API across development, staging, and production environments. Use when setting up multi-environment search pipelines, managing API key isolation, or configuring caching and result limits per deployment tier. Trigger with phrases like "exa environments", "exa staging", "exa dev prod", "exa environment setup", "exa api key by env".

  • 4 stars
  • 0 votes
  • 0 copies
  • 4 views
  • Added September 10, 2026
devopsjavascripttypescriptjavabashnodeawsgitapici/cddocumentation

Works with

  • cli
  • api

Security analysis

A92/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro shows the line behind each finding and how to fix it

Scanned September 10, 2026

npx -y skills add micsapp/micstec-skills --skill exa-multi-env-setup --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Exa Multi Env Setup?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Exa Multi Env Setup
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/micsapp-exa-multi-env-setup/badge)](https://www.skillsdirectory.com/skills/micsapp-exa-multi-env-setup)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: exa-multi-env-setup
description: |
  Configure Exa neural search API across development, staging, and production environments.
  Use when setting up multi-environment search pipelines, managing API key isolation,
  or configuring caching and result limits per deployment tier.
  Trigger with phrases like "exa environments", "exa staging", "exa dev prod",
  "exa environment setup", "exa api key by env".
allowed-tools: Read, Write, Edit, Bash(aws:*), Bash(gcloud:*), Bash(vault:*)
version: 1.0.0
license: MIT
author: Jeremy Longshore <jeremy@intentsolutions.io>
compatible-with: claude-code, codex, openclaw
---
# 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
```typescript
// 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
```typescript
// 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
```bash
# .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
```typescript
// 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
```yaml
# .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
```typescript
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](https://docs.exa.ai)
- [Exa JavaScript SDK](https://github.com/exa-labs/exa-js)
- [Exa Pricing](https://exa.ai/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

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.