Environment variables

Every variable Tick reads, plus the npm scripts you'll use in development.

Variables

Two are required; everything else has a working default. NUXT_PUBLIC_* variables are readable by the browser — that is deliberate, they only carry flags the UI needs.

VariableRequiredDefaultDescription
NUXT_DATABASE_URLyes—Postgres connection string, e.g. postgresql://tick:password@localhost:5432/tick
NUXT_SESSION_PASSWORDyes—Session cookie encryption secret, 32+ chars. Generate: openssl rand -base64 36. Changing it logs everyone out
NUXT_AUTO_MIGRATEnotrueApply pending SQL migrations on production startup — requests get 503 until they finish, and a failure exits the process; false to run them out-of-band (npx drizzle-kit migrate)
NUXT_MIGRATIONS_DIRno<cwd>/server/db/migrationsOverride the migrations folder location
NUXT_PUBLIC_REGISTRATIONnoopenWho may sign up themselves: open (anyone), invite (a valid invite link is required), closed (nobody). See registration modes
NUXT_AUTH_RATE_LIMITno10Max POSTs per IP per minute to each auth endpoint (login/register/forgot/reset); 0 disables it (e.g. when the reverse proxy rate-limits)
NUXT_SESSION_COOKIE_SECUREnotrueSecure flag on the session cookie. false only for plain-HTTP access on a trusted network (see Security). Empty or unrecognized values stop startup
NUXT_SMTP_HOSTno—SMTP server for outgoing mail. Mail is off until this and NUXT_MAIL_FROM are both set
NUXT_SMTP_PORTno465 when secure, else 587SMTP port
NUXT_SMTP_USERno—SMTP username; when unset the connection is unauthenticated
NUXT_SMTP_PASSno—SMTP password / app password
NUXT_SMTP_SECUREnofalsetrue = implicit TLS (usually port 465). Leave unset for STARTTLS on 587
NUXT_MAIL_FROMno—From address, e.g. Tick <tick@example.com>. Required together with NUXT_SMTP_HOST for any mail to go out
NUXT_DEMO_MODEnofalsePublic-demo mode: wipes and reseeds the demo org (see the warning below) and returns 403 for destructive operations — password change, org rename, member removal, invite create/revoke, CSV import commit (preview still works) and permanent trash deletion
NUXT_PUBLIC_DEMO_MODEnofalseShows the dismissible "Demo — data resets nightly" banner in the app shell
NITRO_HOSTno0.0.0.0 (image)Bind address of the production server
NITRO_PORTno3000Port of the production server
POSTGRES_PASSWORDnotickdocker-compose only: password for the bundled Postgres
TICK_PORTno3000docker-compose only: host port the app is published on
TICK_IPno0.0.0.0docker-compose only: host IP the published port binds to — 127.0.0.1 behind a same-host reverse proxy (Docker bypasses ufw/firewalld)
NUXT_DEMO_MODE=true is for throwaway demo instances only. On boot — and then hourly, whenever the last reset is over 24 hours old — it deletes the "Hollow Studio" org and the mara@example.com user, cascading away their clients, projects, tasks, tags and entries, then reseeds three weeks of fake history. Never point a demo-mode instance at a database that holds real data.
Keep NUXT_SESSION_PASSWORD stable across restarts and deploys — it encrypts every session cookie. A changed value logs everyone out.
NUXT_SESSION_COOKIE_SECURE: false/0 disable the Secure flag, true/1 keep it; an empty value or an unrecognized value aborts startup rather than guessing. Behind a TLS proxy leave it unset.
docker-compose.yml passes the database, session, session-cookie, migration, registration, rate-limit and SMTP variables from .env into the app container. Demo mode is deliberately left out — it wipes data, so add NUXT_DEMO_MODE / NUXT_PUBLIC_DEMO_MODE to the app service's environment: block by hand, and only on a throwaway instance. Any other variable needs the same treatment. Plain docker run -e …, PM2 and systemd read variables directly.Compose expands $ inside .env values, so single-quote any secret that contains one: NUXT_SMTP_PASS='pa$$word'.

.env.example at the repo root documents the same set; cp .env.example .env is the starting point for both Docker Compose and development.

Request bodies to /api/* are capped at 1 MB (413 beyond it, 411 if a mutation arrives without a Content-Length); the CSV import routes have their own 5 MB cap. Neither is configurable — raise the proxy's own client_max_body_size to match if you front Tick with nginx or Caddy.

npm scripts

ScriptWhat it does
npm run devDev server with hot reload
npm run buildProduction build to .output/
npm run typecheckvue-tsc over app + server
npm run db:pushSync the Drizzle schema straight to the DB (development)
npm run db:generateWrite a SQL migration from schema changes — commit the server/db/migrations output
npm run db:seedDemo org "Hollow Studio" with ~3 weeks of entries (login: mara@example.com / tick-demo). Re-running it wipes and recreates that org