Environment Variables
Environment variables are scoped at the app level (deployer role) for runtime configuration or at the project level (admin role) for shared infra secrets. Values are encrypted at rest with audit logging.
Endpoint
App-level env vars (/api/apps/:appId/env-vars
, deployer role)
| Method | Path | Auth | Idempotent |
|---|
| GET | /api/apps/:appId/env-vars
| deployer Bearer | yes |
| GET | /api/apps/:appId/env-vars/categories
| deployer Bearer | yes |
| POST | /api/apps/:appId/env-vars
| deployer Bearer | no |
| POST | /api/apps/:appId/env-vars/for-deployment
| deployer Bearer | yes |
| POST | /api/apps/:appId/env-vars/bulk
| deployer Bearer | yes |
| PATCH | /api/apps/:appId/env-vars/:id
| deployer Bearer | no |
| DELETE | /api/apps/:appId/env-vars/:id
| admin Bearer | yes |
| DELETE | /api/apps/:appId/env-vars/
| admin Bearer | yes |
| GET | /api/apps/:appId/env-vars/audit
| admin Bearer | yes |
Project-level env vars (/api/projects/:projectId/env-vars
, admin role)
| Method | Path | Auth | Idempotent |
|---|
| GET | /api/projects/:projectId/env-vars
| admin Bearer | yes |
| POST | /api/projects/:projectId/env-vars
| admin Bearer | no |
| PATCH | /api/projects/:projectId/env-vars/:id
| admin Bearer | no |
| DELETE | /api/projects/:projectId/env-vars/:id
| admin Bearer | yes |
Parameters
| Name | Type | Required | Default | Notes |
|---|
appId
| string | yes (path) | — | App UUID |
projectId
| string | yes (path / query) | — | Project UUID |
key
| string | yes (body) | — | Max 128 chars, matches ^[a-zA-Z0-9_./-]{1,128}$
|
value
| string | yes (body) | — | Max 8KB; encrypted at rest (AES-256) |
target
| string | no | "production"
| Deployment target scope |
branch
| string | null | null
| Branch-specific override |
category
| string | no | null
| Must match ^[a-z0-9][a-z0-9-]{0,49}$
|
isPreview
| boolean | yes (for-deployment) | — | Whether this is a preview deployment |
since
| query | no (audit) | — | ISO 8601 or Nd shorthand (e.g. 7d ) |
limit
| query | no (audit) | — | Max audit log rows to return |
actor
| query | no (audit) | — | Filter audit log by actor identity |
action
| query | no (audit) | — | Filter audit log by action name |
Response
// GET /api/apps/:appId/env-vars — list app env vars
Array<{
id: string;
appId: string;
key: string;
value: string; // decrypted
target: string | null;
branch: string | null;
category: string | null;
createdAt: string;
updatedAt: string;
}>
// GET /api/apps/:appId/env-vars/categories
Array<{
category: string;
count: number;
}>
// POST /api/apps/:appId/env-vars (201)
{
id: string;
appId: string;
key: string;
target: string | null;
branch: string | null;
category: string | null;
createdAt: string;
}
// POST /api/apps/:appId/env-vars/for-deployment
{
envVars: Record<string, string>; // resolved key → value map
}
// POST /api/apps/:appId/env-vars/bulk (201)
{
upserted: number;
errors: Array<{ key: string; error: string }>;
}
// GET /api/projects/:projectId/env-vars — list project env vars
Array<{
id: string;
projectId: string;
key: string;
value: string;
target: string | null;
branch: string | null;
createdAt: string;
}>
// GET /api/apps/:appId/env-vars/audit
{
rows: Array<{
createdAt: string;
actor: string;
action: string;
key: string;
target: string | null;
branch: string | null;
beforeFp: string; // fingerprint of previous value
afterFp: string; // fingerprint of new value
}>;
total: number;
}
// DELETE single — 204 No Content
// DELETE bulk — { deleted: number }
// Error responses
{ error: "Missing appId" } // 400
{ error: "key and value are required" } // 400 (create)
{ error: "category must be lowercase alphanumeric + hyphens, max 50 chars" } // 400
{ error: "max 100 entries per request" } // 400 (bulk)
{ error: "value too large for key ${key}" } // 400 (bulk)
{ error: "duplicate key ${key} in payload" } // 400 (bulk)
{ error: "Env var not found" } // 404
Examples
# List app env vars filtered by category
curl -H "Authorization: Bearer $BF_DEPLOYER_KEY" \
"https://api.blueforge.studio/api/apps/app_xxx/env-vars?category=database"
# List categories for an app
curl -H "Authorization: Bearer $BF_DEPLOYER_KEY" \
https://api.blueforge.studio/api/apps/app_xxx/env-vars/categories
# Create an app env var
curl -X POST https://api.blueforge.studio/api/apps/app_xxx/env-vars \
-H "Authorization: Bearer $BF_DEPLOYER_KEY" \
-H "Content-Type: application/json" \
-d '{"key": "DATABASE_URL", "value": "postgres://...", "category": "database"}'
# Resolve env vars for a deployment
curl -X POST https://api.blueforge.studio/api/apps/app_xxx/env-vars/for-deployment \
-H "Authorization: Bearer $BF_DEPLOYER_KEY" \
-H "Content-Type: application/json" \
-d '{"branch": "main", "isPreview": false}'
# Bulk upsert (max 100 entries)
curl -X POST https://api.blueforge.studio/api/apps/app_xxx/env-vars/bulk \
-H "Authorization: Bearer $BF_DEPLOYER_KEY" \
-H "Content-Type: application/json" \
-d '[{"key": "API_KEY", "value": "sk-...", "target": "production"}]'
# Query audit log
curl -H "Authorization: Bearer $BF_ADMIN_KEY" \
"https://api.blueforge.studio/api/apps/app_xxx/env-vars/audit?since=7d&limit=50"
# Create a project-level env var (admin-only)
curl -X POST https://api.blueforge.studio/api/projects/prj_xxx/env-vars \
-H "Authorization: Bearer $BF_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{"key": "SHARED_SECRET", "value": "s3cr3t", "target": "production"}'
import { Client } from "@blueforge/client"
const client = new Client({ apiKey: process.env.BF_DEPLOYER_KEY })
// List env vars for an app
const envVars = await client.get(`/api/apps/${appId}/env-vars`)
// Create env var
const envVar = await client.post(`/api/apps/${appId}/env-vars`, {
key: "DATABASE_URL",
value: "postgresql://...",
category: "database",
})
// Resolve for deployment
const resolved = await client.post(
`/api/apps/${appId}/env-vars/for-deployment`,
{ branch: "main", isPreview: false }
)
// Bulk upsert
const result = await client.post(`/api/apps/${appId}/env-vars/bulk`, [
{ key: "API_KEY", value: "sk-...", target: "production" },
{ key: "LOG_LEVEL", value: "debug", target: "staging" },
])
Pitfalls
See also
Tested against
- @blueforge/hosting-api: 2.4.1
- Last verified: 2026-07-15