Overview
Infisical is the secret management platform the GAIA team uses to share environment variables and API keys. It gives you:- Central management of secrets across dev/staging/production environments
- Access control with per-user and per-service permissions
- Audit logging for every secret read and change
- Instant revocation when a credential leaks or a teammate leaves
Infisical is optional. Self-hosters and open-source contributors should
skip this page entirely and use plain
.env files — every app falls back to
local environment variables automatically. Infisical is only required in
production (ENV=production).How Infisical Works with GAIA
At startup, each app (API, bots, voice agent) calls its Infisical loader (inject_infisical_secrets() in Python, injectInfisicalSecrets() in TypeScript). The Next.js web app deliberately does not — see Frontend (Web).
- Authentication: authenticates with a machine identity (Universal Auth client ID + secret)
- Secret retrieval: fetches all secrets for the environment matching your
ENVvalue (development,staging, orproduction) - Environment injection: injects each secret into the process environment — only if that variable is not already set
- Application startup: the app reads its settings from the combined environment
- In development, the loader logs a message and continues with your local
.env - In production, the app refuses to start
Team Development Workflow (Recommended)
Team members authenticate as themselves with the Infisical CLI — no machine identity credentials on laptops. You get personal permissions, audit-logged access, personal secret overrides, and instant revocation on offboarding.1
Install the Infisical CLI
2
Log in
infisical login -i inside containers or WSL2.3
Run any task through the CLI
Prefix any mise task with This wraps the task in Any other command works the same way without mise:
infisical:infisical run --env=development -- mise run <task>,
injecting every secret from the development environment before the
processes start. Pass task flags after -- so mise forwards them instead of
reading them itself:.infisical.json tells the CLI which project to use — it contains only the project ID and default environment, no secrets, so it is committed and needs no setup on your part. The project ID is an identifier, not a credential: fetching secrets still requires infisical login with an account that has access to the project.
Infra URLs: the development environment stores localhost URLs (mongodb://localhost:27017, postgresql://...@localhost:5432/...), because mise dev runs the API and web on the host and reaches dockered infra through published ports. Containers do not use these — infra/docker/docker-compose.yml sets the mongo / postgres service hostnames explicitly, and those take precedence over env_file. Putting Docker hostnames in Infisical instead breaks every native run.
Local tweaks: use personal overrides in the Infisical dashboard instead of editing .env — infisical run applies your personal value while teammates keep the shared one.
Offline: the CLI caches previously fetched secrets, so infisical run keeps working without a network connection.
Self-Hosters and Contributors
You do not need Infisical. Copy.env.example to .env in each app directory and fill in the values. See Environment Variables.
If you run your own Infisical project and want GAIA to pull from it in a headless environment, configure a machine identity:
- Create a project at app.infisical.com and add your secrets
- Go to Organization Access Control → Identities → Create Identity with Universal Auth
- Grant it read access to your project
- Add the credentials to your
.env:
Production: Machine Identity
Production authenticates with a single machine identity shared by every service (seeinfra/docker/docker-compose.prod.yml).
- In Infisical: Organization Access Control → Identities → Create Identity (Universal Auth)
- Grant it read access to the project, environment
production - On the Swarm manager, store its credentials:
scripts/docker-entrypoint.sh reads them from /run/secrets/gaia_infisical_machine_identity_* before exec.
Scoping per service later
One identity means any compromised container can read the whole project. To limit that blast radius, create an identity per service, scope each to the paths that service needs, and store its credentials under its own secret names. Then attach them with Compose’s long syntax, which maps a per-service secret onto the canonical name the entrypoint reads:Frontend (Web)
The Next.js app is intentionally not wired to Infisical — it calls no loader. Its environment is sixNEXT_PUBLIC_* variables plus one server-only secret (BLOG_BEARER_TOKEN, used by src/app/api/blog/route.ts).
NEXT_PUBLIC_* values are compiled into the browser bundle at build time, so they are public by definition — anyone can read them from the shipped JavaScript. Storing them in Infisical adds ceremony without adding secrecy. Keep them in apps/web/.env.local locally and in the build environment for CI.
In development the app still picks up Infisical values under mise infisical dev: the CLI injects them into the process environment before Next starts, and Next ranks process.env above .env.local.
In production web deploys to Cloudflare Workers (OpenNext), not the Swarm, so the server-only secret belongs in Cloudflare’s own store:
Troubleshooting
InfisicalConfigError: Infisical is required in production
InfisicalConfigError: Infisical is required in production
Solution: The app resolved
ENV to production — either explicitly, or
because it is unset and the Python loaders default to production — but has
no Infisical credentials. Provide the machine identity credentials (in
production these arrive as Docker Swarm secrets), or set ENV=development
for local work.Incomplete Infisical config: missing ...
Incomplete Infisical config: missing ...
Solution: Only some of
INFISICAL_PROJECT_ID,
INFISICAL_MACHINE_IDENTITY_CLIENT_ID, and
INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET are set. Set all three to enable
Infisical, or remove all three to use local .env only.Authentication failed
Authentication failed
Solution: Verify the client ID and client secret, ensure the machine
identity has read access to the project, and check that the identity is
enabled.
Secrets not loading
Secrets not loading
Solution: Verify the environment slug matches your
ENV value
(development/staging/production), check that the secrets exist in that
environment of the Infisical project, and confirm the identity’s role covers
the secret path.An Infisical value is not being applied
An Infisical value is not being applied
Solution: A local environment variable with the same name is set —
local values always take precedence over Infisical. Unset the local
variable (check your shell and
.env files) to use the Infisical value.Debug Mode
Check the application logs during startup — the loaders log connection, fetch, and injection timing, and any Infisical errors.Security Best Practices
Humans use personal logins
Team members authenticate with
infisical login, never with shared machine
identity credentials. Offboarding a person revokes their access instantly.Scope identities to shrink blast radius
Production currently shares one machine identity across services, so any
compromised container can read the whole project. Splitting it per service
is a compose-only change — see Scoping per service
later.
Environment separation
Use the
development/staging/production environments within the
project, and separate secrets per environment.Rotate and audit
Set client-secret TTLs where possible, rotate leaked credentials
immediately, and review the audit log for unexpected access.
Next Steps
Environment Variables
Configure your environment variables and learn about Infisical integration
Docker Setup
Deploy GAIA with Docker Compose and Infisical secrets
For more detailed Infisical documentation, visit the official Infisical
docs.

