# Environment Variables



Environment variables let you pass configuration and secrets to your functions without hardcoding them.

## Local Development [#local-development]

### Automatic `.env` Loading [#automatic-env-loading]

`ccp dev` automatically loads a `.env` file from your project root:

```bash
# .env
API_KEY=sk-abc123
DATABASE_URL=postgres://localhost:5432/mydb
```

```bash
ccp dev
# Automatically loaded .env file...
```

### Custom Env File [#custom-env-file]

Point to a different file with `--env`:

```bash
ccp dev --env .env.staging
```

### Accessing in Code [#accessing-in-code]

Use `process.env` to read variables:

```ts
export function handler(request: Request): Response {
  const apiKey = process.env.API_KEY;

  if (!apiKey) {
    return new Response("API_KEY not set", { status: 500 });
  }

  return Response.json({ configured: true });
}
```

## Production [#production]

Production environment variables are stored per function and injected into your deployment at runtime. Set them by `PATCH`-ing the function via the serverless API:

```bash
curl -X PATCH https://api.clusterbase.dev/api/v1/serverless/functions/<FUNCTION_ID> \
  -H "Authorization: Bearer $(ccp auth print-access-token)" \
  -H "Content-Type: application/json" \
  -d '{
    "environment_variables": {
      "API_KEY": "sk-abc123",
      "DATABASE_URL": "postgres://..."
    }
  }'
```

The function ID is in your `.ccp/config.json`. A UI for managing these in the console is coming soon.

### How env updates merge [#how-env-updates-merge]

When you deploy (or `PATCH` the function), Clusterbase **merges** the env you send into the function's existing variables: keys you include are added or updated, and keys you don't include are left untouched. So server-side managed values — like the `DATABASE_HTTP_URL` and `DATABASE_HTTP_TOKEN` (and, for networked Apps bound to a database, the native `DATABASE_URL`) that [`ccp db create`](/docs/ccp/database) injects — survive a code-only redeploy even when they aren't in your local `.env`.

Because updates merge, removing a key from your `.env` (or from the `PATCH` body) no longer deletes it from the function — the old value stays. Value *changes* still take effect; only key *removal* is a no-op. There is no function-env delete API yet, so to drop a variable entirely, destroy and recreate the function.

### Updates redeploy the function [#updates-redeploy-the-function]

Updating env republishes the function's active production deployment so the new values take effect on the running deployment immediately — expect a brief window during which the function is momentarily unavailable while the deployment is rebuilt. If the env write itself fails, the request returns `500` with `{"error": "env_update_failed"}` instead of a misleading `200` — a failed update is surfaced, never silently dropped.

## `.env` in `.gitignore` [#env-in-gitignore]

The `ccp init` command adds `.env` to `.gitignore` by default. Never commit secrets to your repository.
