.env file next to docker-compose.yaml: see Docker Compose. A change takes effect when the postqueen container is recreated, not restarted:
NEXT_PUBLIC_variables need no rebuild. The web app renders its pages on the server and hands these values to the browser at run time, so recreating the container is enough. The one exception isNEXT_PUBLIC_APP_VERSION, which is fixed when the image is built.- The start-up check only warns. After the backend is listening it checks the required values below and logs each problem as a
Configuration issue. Nothing stops, so a running container is not proof that the settings are right:docker compose logs postqueen | grep -i "configuration issue". - The backend and the orchestrator read the same variables. In the official image both run in one container. If you run them apart, give both the same environment.
Required
The start-up check reports these when they are missing, and URLs when they are not valid or end in/.
Encryption keys
A channel’s OAuth access and refresh tokens, the ones a network hands back after sign-in, are encrypted with the same key. Tokens stored before that are encrypted when the app starts. A token is re-encrypted under a new key only when it is next written, and some never expire, so keep
PREVIOUS_ENCRYPTION_KEY set after a rotation. Treat a database dump as sensitive all the same.
- On a new install, set
ENCRYPTION_KEYto its own random value before there is data.JWT_SECRETthen only signs sessions, and rotating it only signs people out. - On an install that never set it, set
ENCRYPTION_KEYto the current value ofJWT_SECRET. Nothing needs re-encrypting, because that is the key already in use. After that you can rotateJWT_SECRETfreely. - To rotate
ENCRYPTION_KEY, copy the current value intoPREVIOUS_ENCRYPTION_KEY, put the new value inENCRYPTION_KEY, and recreate the container. Leave both set: a row is re-encrypted only when something rewrites it, so data nobody touches stays on the old key.
How switches are read
PRISMA_MIGRATE has its own rule: see Background work.
Sign-up and sign-in
Sign-in buttons
Set the four Apple values together: the button appears with
APPLE_CLIENT_ID alone and fails without the rest.
Background work
Temporal runs the schedule, and the orchestrator runs its workers. See Self-hosting overview.Storage and media
Setup and trade-offs: Uploads and storage and Cloudflare R2.Limits and safety
Networks
Each network’s developer app variables, redirect URI and setup page are on Channel developer apps. Eight networks read no variable: Bluesky, DEV, Hashnode, Lemmy, Listmonk, Moltbook, Nostr and WordPress.
Kick’s secret is
KICK_SECRET, and Dribbble’s variables are spelled with three b characters.
Farcaster
The channel connects through a Neynar managed signer, which the person approves by scanning a QR code in the Farcaster app. There is no redirect URI.NEYNAR_APP_FID, NEYNAR_APP_MNEMONIC and NEYNAR_SPONSOR_SIGNERS are not listed in the Compose file’s YAML; the .env file passes them through. Setup: Farcaster setup.
Hide or move a network
The identifier is the last part of the connect address, such as
tiktok in /integrations/social/tiktok. The two are usually set together: hide the network you retire, and its channels move on their next reconnect.
MCP and OAuth apps
Details: MCP on your server.AI
Billing
A private install needs none of this: without both Stripe keys there is no billing and every workspace has every feature.Interface
Short links
Setup: Short links. The first one configured in this order wins:DUB_TOKEN (with DUB_API_ENDPOINT, DUB_SHORT_LINK_DOMAIN), SHORT_IO_SECRET_KEY, KUTT_API_KEY (with KUTT_API_ENDPOINT, KUTT_SHORT_LINK_DOMAIN), LINK_DRIP_API_KEY (with LINK_DRIP_API_ENDPOINT, LINK_DRIP_SHORT_LINK_DOMAIN).
Newsletter for new sign-ups
These add each new account’s email address to a mailing list you run. They have nothing to do with posting.LISTMONK_* does not configure the Listmonk channel. The channel takes its server address and API user in the connect form: see Channel developer apps.Analytics and error tracking
All optional.Listed in example files, but not read
These appear in the Compose file or.env.example and change nothing: FEE_AMOUNT, NX_ADD_PLUGINS, SLACK_SIGNING_SECRET, STRIPE_SIGNING_KEY_CONNECT, POSTQUEEN_OAUTH_URL and BACKEND_URL. MCP_URL is passed to the web app, but no page uses it: the MCP addresses on Connections come from NEXT_PUBLIC_BACKEND_URL.
Related
- Docker Compose: where the variables go
- Channel developer apps
- Self-hosting troubleshooting