How secrets work
Storage
Secrets are key-value pairs stored in thesecrets table, one row per variable. Before a secret’s value is written to the database, it is encrypted with AES-256-GCM using the ENCRYPTION_KEY environment variable:
- A random 16-byte IV is generated for every encryption operation, so the same plaintext produces a different ciphertext each time.
- An authentication tag is derived from the ciphertext and stored alongside it, allowing the decryption step to detect any tampering.
- The stored value is a single colon-delimited string:
<iv-hex>:<auth-tag-hex>:<ciphertext-hex>.
ENCRYPTION_KEY.
Build-time injection
When a build starts, the engine fetches the project’s secrets, decrypts each value in memory, and writes them to a.env file inside the temporary build directory:
.env file is passed to the Docker container via the --env-file flag:
Database schema
Managing secrets
Adding secrets
Secrets are attached to a project at creation time or any time the project is updated:secrets array in the request body. Each element is a { key, value } object. The server encrypts each value before inserting it.
Deleting a secret
Individual secrets can be removed by their database ID:Security implications
Static deployments are blocked for projects with secrets
If a project has any secrets, the build pipeline sets an internalhasEnvFile flag and skips the automatic deployment step after a successful build. This is intentional: a static site is served directly from the filesystem and any values baked into the build output would be publicly readable.
Projects that require environment variables should be hosted behind a server-side runtime that reads secrets from the environment at request time — not embedded in a static bundle.
Secrets never appear in API responses
Thevalue field is never decrypted when returning project or secret data through the API. Only the key (variable name) and metadata such as id and createdAt are included in responses.
Configuration
The Store this value securely. If it is lost or rotated, all previously encrypted secrets become unrecoverable and will need to be re-entered.
ENCRYPTION_KEY environment variable must be set to a 32-byte value encoded as a 64-character hexadecimal string. Generate a suitable value with: