← Blog

Claude API Key Environment Variables: Best Practices

2026-10-19 · 5 min read · SubToAPI Team

If you're asking how to handle Claude API key environment variables correctly, the short answer is: never hardcode the key, load it from a .env file locally, inject it via your platform's secret manager in production, and scope separate keys per environment so a leak in one place doesn't compromise everything else.

The longer answer involves a handful of concrete habits that most teams skip early on and regret later — mixing dev and prod keys, committing .env files by accident, or giving every service the same unrestricted key. This guide walks through the practical setup, from naming conventions to CI/CD injection to rotation, so your Claude integration stays secure without slowing down development.

Why environment variables, not hardcoded strings

An API key hardcoded in source code ends up in git history forever, even if you delete it in a later commit. It also gets copied into forks, pasted into Slack threads during debugging, and shipped to client-side bundles if you're not careful. Environment variables solve this by keeping secrets out of the codebase entirely — they live in the runtime environment, not the repository.

The pattern is the same regardless of which provider you're calling:

export CLAUDE_API_KEY="sk-ant-..."
const apiKey = process.env.CLAUDE_API_KEY;

Simple, but the details matter: how you name the variable, where it's stored per environment, and who/what can read it.

Naming conventions that scale

Pick a consistent prefix and stick to it across every service. A common pattern:

CLAUDE_API_KEY_DEV
CLAUDE_API_KEY_STAGING
CLAUDE_API_KEY_PROD

If you're using a proxy or gateway layer — which is common once you have multiple apps calling Claude and need usage tracking per app — name the variable after the gateway, not the underlying provider, so swapping implementations later doesn't require renaming everything downstream:

SUBTOAPI_KEY=sub_live_...

This separation matters more than it looks: when the variable name reflects the immediate consumer (your gateway) rather than the ultimate provider, you can change providers or add a routing layer without touching every service's config.

Local development with .env files

Use a .env file for local development, loaded via dotenv or your framework's built-in support:

# .env
CLAUDE_API_KEY=sk-ant-dev-key-here
SUBTOAPI_KEY=sub_live_dev_key_here
import 'dotenv/config';

const key = process.env.SUBTOAPI_KEY;

Two non-negotiable rules:

  1. Add .env to .gitignore before you create it, not after.
  2. Commit a .env.example with placeholder values so new contributors know which variables are required, without ever seeing a real key.
# .env.example
CLAUDE_API_KEY=
SUBTOAPI_KEY=

Separate keys per environment and per app

Don't reuse the same key across dev, staging, and production. If a key leaks from a staging deployment, you want its blast radius limited to staging — not your production billing and rate limits.

The same logic applies horizontally: if you have three internal apps calling Claude, issue three separate keys rather than sharing one. This is where a dashboard that supports multiple application keys under one account becomes useful instead of a nuisance. SubToAPI issues sub_live_... keys per application from a single team account, so you get the isolation benefit (one compromised key = one app affected) without managing N separate provider subscriptions. You can create and label keys per app from the dashboard after signing up at /signup.

Injecting secrets in CI/CD and production

Never put real keys in CI config files, even "private" ones. Use your CI provider's secrets store:

Example GitHub Actions snippet:

jobs:
  test:
    steps:
      - name: Run integration tests
        env:
          SUBTOAPI_KEY: ${{ secrets.SUBTOAPI_KEY }}
        run: npm test

In production, prefer a managed secret store (AWS Secrets Manager, GCP Secret Manager, HashiCorp Vault, or your PaaS's built-in env var UI) over plain environment variables set in a Dockerfile or systemd unit file. Those get logged in process inspection tools and shell history far more often than people expect.

Never expose the key client-side

Any variable prefixed with NEXT_PUBLIC_, VITE_, or REACT_APP_ gets bundled into the JavaScript shipped to the browser. If your Claude or SubToAPI key ends up in one of those, it's public — full stop. Always call the API from a server-side route or backend service, and keep the key server-only:

// pages/api/chat.js — server-side only
export default async function handler(req, res) {
  const response = await fetch('https://api.subtoapi.app/v1/messages', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.SUBTOAPI_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(req.body),
  });
  const data = await response.json();
  res.status(200).json(data);
}

See /docs/quickstart and /docs/messages for the full request/response shape, and /docs/streaming if your backend route needs to pass through streamed tokens instead of waiting for the full completion.

Rotation and revocation hygiene

Environment variable discipline only works if rotation is easy. Store keys in a system that lets you revoke and reissue without a deploy — most secret managers and the SubToAPI dashboard support this directly, so a compromised key can be killed in seconds rather than requiring a code change and redeploy. Check /pricing if you're evaluating per-seat key management for a team, since Solo, Team, and Scale plans differ mainly in how many keys and seats you get, not in the underlying security model.

A simple checklist to audit your current setup:

Questions

Should I use one Claude API key for my whole team or one per developer? One per environment or per app is usually enough — you don't need a key per developer unless you need to attribute usage to individuals. What matters more is isolating dev/staging/prod and giving each application its own key so a leak is contained.

Is it safe to put a Claude API key in a Docker ENV instruction? No. ENV values in a Dockerfile get baked into the image layer and are visible via docker history and docker inspect. Pass secrets at runtime via --env-file, orchestrator secrets, or a mounted secret volume instead.

What's the fastest way to recover if a key leaks? Revoke it immediately from your provider or dashboard, issue a new one, update the secret in your CI/CD and hosting platform, and redeploy. Having a secret manager or a dashboard that supports instant revocation — rather than editing config files by hand — is what makes this a two-minute fix instead of a half-day incident.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →