Environment Variables
Web (apps/web)
| Variable | Required | Default | Description |
|---|---|---|---|
VITE_API_URL | No | "" | Base URL of the API server. Empty means same origin. In local dev, Vite proxies /api to localhost:3001 so this is not needed. |
VITE_ADMIN_ADDRESSES | No | "" | Comma-separated Stellar public keys allowed onto /admin. Client-side only, and inlined into the public build like every VITE_ variable. It is a placeholder gate for the Keeper Health/Vault State panels until #614 lands real server-enforced admin auth. Never treat this as access control for anything sensitive. |
API: serverless (api/v1/) and Fastify (apps/api-local)
| Variable | Required | Default | Description |
|---|---|---|---|
STELLAR_NETWORK | No | "mainnet" | Selects the network the API talks to. Any value other than "testnet" resolves to mainnet, the product's live deployment; testnet requires setting this explicitly. Controls which CONTRACT_ADDRESSES/STELLAR_NETWORKS entry (packages/shared/src/constants.ts) is used for every contract call the API makes. .env.example sets testnet explicitly for local development. |
DEFINDEX_VAULT_ID | No | "" | Overrides the DeFindex vault contract address at runtime. When empty, the address from CONTRACT_ADDRESSES.testnet.defindex.vault in packages/shared/src/constants.ts is used. Blend and vault contract addresses are always sourced from constants. |
PORT | No | 3001 | Fastify server port (local dev only). |
ALLOWED_ORIGIN | No | "https://usemeridian.vercel.app" | CORS allowed origin for the Fastify server. Set to your frontend domain in production if running Fastify as a standalone server. |
REDIS_URL | No | "" | Redis URL for @fastify/rate-limit in apps/api-local (ioredis). Unset: in-memory store (single process); production: set for distributed rate limits. |
UPSTASH_REDIS_REST_URL | Yes (prod) | "" | Upstash Redis REST endpoint. Backs distributed rate limiting (api/_lib/middleware.ts) and the keepers' cross-invocation submission records. The API refuses to start without it when VERCEL_ENV=production; the migration keeper refuses on any deployment, preview included, since preview also signs real transactions. UPSTASH_REDIS_REST_KV_REST_API_URL (the name Vercel's Upstash Marketplace integration provisions) is accepted as a fallback if this isn't set. |
UPSTASH_REDIS_REST_TOKEN | Yes (prod) | "" | Auth token for UPSTASH_REDIS_REST_URL. Same requirement and same consumers. UPSTASH_REDIS_REST_KV_REST_API_TOKEN is accepted as a fallback, same as its URL counterpart. |
CRON_SECRET | Yes | "" | Bearer token required by scheduled keeper endpoints in production and preview deployments. Only true local dev (no VERCEL_ENV set) is permissive without it. |
MERIDIAN_KEEPER_SECRET_KEY | Yes (keeper) | "" | Stellar secret seed for the funded account that submits Blend accrue() transactions. Store in a secrets manager or deployment environment variables; never commit it. |
MERIDIAN_KEEPER_MAX_ATTEMPTS | No | 3 | Maximum attempts per submission. Shared by both the accrue keeper and the migration keeper (rebalance.ts), not accrue-specific despite the name; sizing it affects both. |
MERIDIAN_KEEPER_RETRY_BASE_DELAY_MS | No | 1000 | Initial exponential-backoff delay for transient keeper failures. Shared by both the accrue keeper and the migration keeper. |
MERIDIAN_KEEPER_RPC_TIMEOUT_MS | No | 10000 | Timeout for keeper RPC calls, in milliseconds. Shared by both the accrue keeper and the migration keeper. Fully governs submission calls; discovery reads are additionally capped at a hardcoded 10s ceiling shared with the rest of stellar-sdk-helpers, so values above 10000 only extend the submission side. |
MERIDIAN_KEEPER_SUBMISSION_TTL_MS | No | 360000 | How long a recorded, still-unconfirmed keeper submission keeps blocking a new one for the same target, in milliseconds. Defaults to the 300s transaction validity window plus 60s of clock-skew margin; past it the transaction can never land, so the record is cleared and a retry is allowed. Rejected below 300000, since a shorter window would expire the record while its transaction can still land. Shared by both keepers. See apps/docs/operations/migration-keeper.md. |
MERIDIAN_MIGRATION_KEEPER_SECRET_KEY | Yes (keeper) | "" | Stellar secret seed for the migration keeper. Must be the vault's actual admin address; migrate_adapter is admin-gated, unlike the permissionless accrue(), so this key carries full vault admin authority. Deliberately separate from MERIDIAN_KEEPER_SECRET_KEY. See apps/docs/operations/migration-keeper.md. |
MERIDIAN_MIGRATION_MAX_SLIPPAGE_BPS | No | 100 | max_slippage_bps passed to every migrate_adapter call. The config loader rejects anything above 500, the contract's own MAX_ADMIN_SLIPPAGE_BPS hard cap (#557). |
MERIDIAN_MIGRATION_MIN_IMPROVEMENT_BPS | No | 50 | Minimum rate improvement, in basis points, a candidate protocol must clear before the keeper migrates to it. |
MERIDIAN_ADAPTER_<PROTOCOL>_ID | No | "" | Candidate adapter contract address the migration keeper may migrate the vault to, one var per protocol (e.g. MERIDIAN_ADAPTER_BLEND_ID, MERIDIAN_ADAPTER_DEFINDEX_ID). Not a fixed list: any <PROTOCOL> is picked up automatically, adding a new protocol needs no code change. Unset excludes that protocol from consideration, no fallback default. |
MERIDIAN_ALERT_WEBHOOK_URL | Yes (keeper) | "" | Slack or Discord incoming-webhook URL the admin-event alert keeper posts to. See apps/docs/operations/alert-keeper.md. |
Deploy scripts (scripts/)
These are shell environment variables read by scripts/deploy-testnet.sh and scripts/redeploy-blend-adapter.sh at deploy time, not application runtime variables, and not read from .env files.
| Variable | Required | Description |
|---|---|---|
DEPLOYER | Yes (both scripts) | A funded Stellar secret key that pays transaction fees and signs setup calls only. It is disposable and does not need to be kept after the script finishes. |
ADMIN | No (deploy-testnet.sh only) | A public key that becomes the deployed vault's permanent admin. Defaults to DEPLOYER's own address if unset (with a warning), but a throwaway default is unsuitable past a quick test. Set it explicitly to a separate, durable key; it is required ahead of mainnet. |
USDC_ID | No | Overrides the testnet USDC contract address the deployed adapter/vault is wired to. |
BLEND_POOL_ID | No | Overrides the testnet Blend pool address the deployed BlendAdapter is wired to. |
VAULT_ID | Yes (redeploy-blend-adapter.sh only) | The already-live vault contract ID to eventually point at the newly deployed adapter via set_adapter. |
deploy-testnet.sh prints three contract IDs on success (VAULT_CONTRACT_ID, BLEND_ADAPTER_CONTRACT_ID, MUSDC_CONTRACT_ID). None of these are environment variables the app reads either; VAULT_CONTRACT_ID and MUSDC_CONTRACT_ID need to be copied into CONTRACT_ADDRESSES/KNOWN_POOLS in packages/shared/src/constants.ts and packages/stellar-sdk-helpers/src/known-pools.ts respectively. See Testnet Deployment.
Vercel
Set environment variables in the Vercel dashboard under Project Settings > Environment Variables, or via the CLI:
vercel env add DEFINDEX_VAULT_IDVariables prefixed with VITE_ are inlined at build time and exposed to the browser. Do not put secrets in VITE_ variables.
Local development
Create .env files at the package level if needed:
# apps/api-local/.env
PORT=3001
DEFINDEX_VAULT_ID=C... # optional, leave empty to use the address in constants.tsThe Fastify server loads .env via the dotenv package on startup.