Skip to content

The .env file

The .env file holds everything that belongs to this one installation of your CMS: passwords, secrets, ports, addresses and a few switches. Everything else lives in the config files, which read their values from here. That split is why the same project can run on your laptop and on a server: only .env differs.

manablox create wrote a complete .env for you, with fresh random secrets. You can run the CMS without changing anything in it. This page explains what each line means, so you know what to change when the time comes.

.env is a plain text file with one setting per line, in the form NAME=value. Lines starting with # are comments. There are no spaces around the =, and values need no quotes. For example:

Terminal window
# The port of the admin
PORT=3000
MAIL_DRIVER=mailpit
MAIL_FROM=Manablox <no-reply@localhost>

These settings are called environment variables. An empty value (S3_BUCKET=) counts as not set.

.env.example is the same file with every secret left blank. It is safe to commit to Git and to share, so a teammate can copy it to .env and fill in their own secrets.

In a local project .env is read twice:

  • by Docker Compose, when you run pnpm services:up: it takes the ports (and, with Postgres, the database passwords) from it,
  • by the manablox command, every time you run pnpm dev, pnpm migrate or another manablox command: it loads .env from the project folder before it reads the config files.

A variable that is already set in your terminal wins over the file. So PORT=3200 pnpm dev (on macOS and Linux) starts the CMS on port 3200 for this one run, whatever .env says.

Changes to .env are not picked up while the CMS runs, not even by pnpm dev. After editing it, press Ctrl+C and start the CMS again. If you changed a Postgres or Valkey setting, also run pnpm services:down and pnpm services:up.

Only in a local project. These say where Docker publishes the database and the cache, and how the CMS reaches them.

VariableDefaultWhat it means
POSTGRES_PORT5432The port the database is reachable on from your computer. Only with Postgres
VALKEY_PORT6379The port of Valkey, the cache and job queue
DATABASE_URLpostgres://manablox:<password>@localhost:5432/manabloxHow the CMS connects to the database: user, password, host, port and database name. With SQLite it is file:./data/manablox.db, the database file
PUBLIC_DATABASE_URLthe same with the user manablox_publicHow the public API connects, as a user that may only read. Only with Postgres; with SQLite the public API uses DATABASE_URL
REDIS_URLredis://localhost:6379How the CMS connects to Valkey
PORT3000The port of the admin and the management API
PUBLIC_URLhttp://localhost:3000The address the admin is opened at in a browser. Used for links in emails, image addresses and login
PUBLIC_PORT3100The port of the public API
PUBLIC_API_URLhttp://localhost:3100The address the public API is reached at

When to change them: when a port is already in use on your computer. Some values appear twice and must match:

  • POSTGRES_PORT and the port inside DATABASE_URL and PUBLIC_DATABASE_URL,
  • VALKEY_PORT and the port inside REDIS_URL,
  • PORT and the port inside PUBLIC_URL,
  • PUBLIC_PORT and the port inside PUBLIC_API_URL.

For example, if another Postgres already uses 5432, set POSTGRES_PORT=5433 and change localhost:5432 to localhost:5433 in both database URLs. Then run pnpm services:down and pnpm services:up.

DATABASE_URL also decides which database the CMS uses: postgres://... for Postgres, file:... for a SQLite file, libsql://... for a hosted SQLite database. See The database.

A docker project has domain and port settings here instead (ADMIN_DOMAIN, PUBLIC_DOMAIN, ACME_EMAIL, ADMIN_PORT, UPLOAD_BODY_LIMIT and the two URLs). They are explained in Domains and HTTPS.

VariableWhat it means
POSTGRES_PASSWORDThe password of the database user manablox. Docker sets it when the database is created. Only with Postgres
POSTGRES_PUBLIC_PASSWORDThe password of the read-only user manablox_public, used by the public API. Only with Postgres
AUTH_SECRETThe main secret of your CMS. It signs logins and image addresses, and it encrypts the credentials and AI keys stored in the admin
MEDIA_SIGNING_SECRETOptional. A separate secret just for image addresses. Empty means AUTH_SECRET is used

manablox create filled these with long random values. Keep them secret, and keep them the same once the CMS is in use:

  • Changing AUTH_SECRET signs everyone out, changes every image address (so caches and CDNs fetch them anew), and makes every credential and AI key stored in the admin unreadable: they have to be entered again.
  • Changing MEDIA_SIGNING_SECRET only changes the image addresses. Setting it lets you change one secret without the other.
  • Changing POSTGRES_PASSWORD or POSTGRES_PUBLIC_PASSWORD in .env does not change the password inside an existing database. Docker only uses these values when it creates the database the first time. If you change them anyway, the CMS can no longer connect.

To make a new random secret, for example for a new server, run this in a terminal and paste the output into .env:

Terminal window
openssl rand -hex 32

This prints 64 random letters and digits (only 0 to 9 and a to f), so the value is also safe inside a database URL. The comment above the secrets in .env suggests the same command.

Only in a project with the public API.

VariableDefaultWhat it means
MANABLOX_SPACEemptyThe technical name of the one space the public API serves. With exactly one space it can stay empty; with several the public API refuses to start until you set it
PUBLIC_CACHE_TTL300How many seconds an answer of the public API may be reused by caches. See Caching
PUBLIC_GRAPHQL_INTROSPECTIONfalsetrue lets GraphQL tools read the schema of the public API. Useful while building a website, off by default because the API is public
VariableDefaultWhat it means
CORS_ORIGINSemptyAddresses of your own websites that call the management API from the browser, separated by commas, for example http://localhost:3005. The admin itself needs no entry

You need this when your website shows previews or uses the visual editor, which talk to the management API. See Preview and the visual editor. A website that only reads published content from the public API needs no entry.

These groups have their own pages:

  • STORAGE_DRIVER, STORAGE_LOCAL_PATH, MEDIA_CACHE_PATH, PUBLIC_MEDIA_CACHE_PATH, the S3_* variables and FILE_MAX_SIZE_MB: see Uploads and images.
  • MAIL_DRIVER, MAIL_FROM and the variables of each mail service: see Sending email.
  • LOG_LEVEL and the other LOG_* variables: see Logs.
VariableDefaultWhat it means
AI_ALLOWED_HOSTSemptyAddresses on your own network that a self-hosted AI model may be reached at, separated by commas, as host or host:port, for example localhost:11434 for Ollama on your computer. Public AI providers need no entry
WORKFLOWS_ALLOW_PRIVATE_NETWORKfalsetrue lets workflow HTTP steps and webhooks reach addresses on your own network and on this computer (localhost). Only turn it on for an installation you trust that is not open to others

Without an entry in AI_ALLOWED_HOSTS, the admin refuses to connect to a model on your own network and names the address you have to add. Restart the CMS after changing either variable. See AI.

VariableDefaultWhat it means
PUSH_VAPID_PUBLIC_KEYemptyThe public half of the key pair for browser push notifications
PUSH_VAPID_PRIVATE_KEYemptyThe private half. Keep it secret
PUSH_VAPID_SUBJECTmailto:admin@localhostA contact address that push services may use. Put your own address here

While the keys are empty, notifications reach people in the admin (and by email, if mail is set up), but not as browser push. pnpm push-keys prints a pair; see Everyday commands. Set them once and never change them: new keys break every browser that already subscribed.

VariableDefaultWhat it means
LOG_LEVELinfoHow much the CMS writes to its log. See Logs
DB_POOL_MAX10How many database connections one CMS process may hold at once. The default is fine for most sites

Your config files read a few more variables that are not in .env by default. Add a line to .env when you need one.

VariableDefaultWhat it means
HOST0.0.0.0The network address the CMS listens on. 0.0.0.0 means every address of the machine; 127.0.0.1 means only this computer
ADMIN_URLthe value of PUBLIC_URLWhere links in workflow emails and notifications point. Only needed if the admin is reached at another address than the API
DATABASE_SSLfalsetrue connects to the database over an encrypted connection, which many hosted Postgres services require
DATABASE_AUTH_TOKENemptyOnly for a hosted SQLite (libSQL) database such as Turso: the access token your provider gives you. See The database
CACHE_ENABLEDtruefalse turns the response cache off completely
CACHE_TTL60Seconds an answer stays in the response cache of the CMS process. The public API uses PUBLIC_CACHE_TTL instead
CACHE_SYNC_INTERVAL5Only without Valkey: how many seconds the CMS and the public API wait between checks for content types the other one saved. 0 turns the check off
GRAPHQL_MAX_DEPTH12How deeply nested a GraphQL query to the management API may be
NODE_ENVemptyproduction switches the CMS to production behaviour: GraphQL introspection off, error details hidden, logs as JSON
ALLOWED_MIME_TYPESimages, video, audio, text, PDF and office filesWhich kinds of files may be uploaded. See Uploads and images
MANABLOX_SPACE_IDemptyLike MANABLOX_SPACE, but by the space’s id. Wins over MANABLOX_SPACE
PUBLIC_GRAPHQL_MAX_DEPTH8How deeply nested a query to the public API may be
PUBLIC_GRAPHQL_MAX_COMPLEXITY1000How expensive a single query to the public API may be
RATE_LIMITonoff turns off the limit of 300 requests per minute per visitor on the public API