Uniform stock management for healthcare linen rooms: the coordinator app, the phone counter and the staff app, for your own server. Built from 38e16eb on 2026-09-15. Licensed under the Functional Source License (FSL-1.1-ALv2).
5.6 KiB
title, section, order, summary, role, keywords
| title | section | order | summary | role | keywords |
|---|---|---|---|---|---|
| Configuration reference | selfhost | 6 | Every environment variable, whether it is required, its default and what it does, with the hosted-only ones marked. | Self-hosting admin | configuration, environment, variables, env, .env, settings, reference, session secret, smtp, turnstile, signups disabled, app port, edition, hosted only |
How settings are read
Settings go in .env in the checkout. docker-compose.yml passes the whole file to the app container, then sets five values itself, and those win over .env:
| Variable | Set by compose to |
|---|---|
DATABASE_URL |
The bundled db service, using POSTGRES_PASSWORD |
EDITION |
community |
PHOTO_DIR |
/data/photos |
PORT |
3000 |
HOSTNAME |
0.0.0.0 |
Variables starting NEXT_PUBLIC_ are compiled into the app when the image is built. The build does not read .env: compose passes only NEXT_PUBLIC_SITE_URL and NEXT_PUBLIC_TURNSTILE_SITEKEY into it. Any other NEXT_PUBLIC_ variable in .env has no effect on a Docker install. A change to either of those two needs docker compose up -d --build; any other change needs docker compose up -d.
The repository's .env.example lists the variables the Community edition reads. The tables below also list the ones only threadcount.tech uses, marked hosted only, so you know they can stay blank.
Required
| Variable | Default | What it does |
|---|---|---|
SESSION_SECRET |
change-me |
Signs every session cookie. The server refuses to start with the placeholder or with none. Make one with openssl rand -base64 48. |
POSTGRES_PASSWORD |
none | The bundled database's password. Compose refuses to start without it. |
NEXT_PUBLIC_SITE_URL |
http://localhost:3000 |
The address people open. Every link in an email is built from it. Build-time. |
EDITION |
none | community. Turns off plans, the staff ceiling, the demo and reporting to ThreadCount, and makes Turnstile optional. |
DATABASE_URL |
set by compose | The Postgres connection. Required outside compose. |
See email.
| Variable | Default | What it does |
|---|---|---|
SMTP_HOST |
none | Mail server. Mail is on only when this, SMTP_USER and SMTP_PASS are all set. |
SMTP_PORT |
587 |
465 connects with TLS from the start. |
SMTP_USER |
none | Mail server login |
SMTP_PASS |
none | Mail server password |
SMTP_FROM |
SMTP_USER |
The From line |
CONTACT_TO |
none | Hosted only. Where the website's contact form is delivered. |
Switches and the server
| Variable | Default | What it does |
|---|---|---|
SIGNUPS_DISABLED |
open | 1 hides facility sign-up and refuses the sign-up endpoint. |
APP_PORT |
3000 |
The port on the server the app is published on. Compose reads it; the container always listens on 3000. |
PHOTO_DIR |
set by compose | Where signatures and photos are written. Back it up with the database. |
TURNSTILE_SECRET |
none | Cloudflare Turnstile on sign-in, sign-up and password reset. Enforced only when set. |
NEXT_PUBLIC_TURNSTILE_SITEKEY |
none | Turnstile's site key. Build-time. Set both or neither. |
TURNSTILE_OPTIONAL |
none | 1 lets production run without Turnstile. For local tests; a Community instance does not need it. |
DB_POOL_MAX |
the driver's default | Local development only. 1 makes every database call wait for the one before. Never set it on a server. |
Documents, errors, statistics and chat
These are all NEXT_PUBLIC_ variables, so as the first section explains, they have no effect on a Docker install today.
| Variable | Default | What it does |
|---|---|---|
NEXT_PUBLIC_TERMS_URL |
none | Your terms page, linked from the staff sign-in and account screens. With none, no link shows. |
NEXT_PUBLIC_PRIVACY_URL |
none | Your privacy notice, linked the same way |
NEXT_PUBLIC_GLITCHTIP_DSN |
none | Your own GlitchTip or other Sentry-protocol address for error reports. With none, nothing is reported. |
NEXT_PUBLIC_RELEASE |
none | A label stamped on error reports; also shown as version at /api/app-info when there is no COMMUNITY_VERSION file |
NEXT_PUBLIC_UMAMI_SRC |
none | Your own Umami tracker script. With none, no statistics are sent. |
NEXT_PUBLIC_UMAMI_SITE_ID |
none | Umami site id |
NEXT_PUBLIC_UMAMI_APP_ID |
none | Umami id for the app |
NEXT_PUBLIC_CHATWOOT_URL |
none | Your own Chatwoot. With this and the token set, a chat widget shows in the coordinator app. |
NEXT_PUBLIC_CHATWOOT_TOKEN |
none | Chatwoot website token |
Hosted only
Nothing in the Community edition reads these. Leave them blank.
| Variable | Used on threadcount.tech for |
|---|---|
JACKSON_URL, JACKSON_API_KEY |
Single sign-on for facilities |
CF_ACCESS_TEAM_DOMAIN, CF_ACCESS_AUD |
Sign-in to ThreadCount's own staff tools |
STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, STRIPE_PRICE_MONTHLY, STRIPE_PRICE_ANNUAL, NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY |
Card payments |
INVOICE_ENTITY, INVOICE_ABN |
Who invoices hosted plans |
PLANS_LIVE |
Forcing plans on. Ignored when EDITION=community. |
DEMO_DISABLED, DEMO_RESET_TOKEN |
The public demo facility |
ANDROID_APP_FINGERPRINTS_COUNTER, ANDROID_APP_FINGERPRINTS_STAFF |
Android App Links for ThreadCount's own Play apps |
LISTMONK_URL, LISTMONK_LIST_UUID |
The product-update mailing list |
CHATWOOT_URL, CHATWOOT_API_TOKEN, CHATWOOT_ACCOUNT_ID, CHATWOOT_INBOX_ID |
Filing contact-form messages in the helpdesk |
threadcount.tech's own settings file has four more variables, for its internal administration. The Community edition does not contain that code.