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.
| Variable | Required | Default | Description |
|---|---|---|---|
NUXT_DATABASE_URL | yes | — | Postgres connection string, e.g. postgresql://tick:password@localhost:5432/tick |
NUXT_SESSION_PASSWORD | yes | — | Session cookie encryption secret, 32+ chars. Generate: openssl rand -base64 36. Changing it logs everyone out |
NUXT_AUTO_MIGRATE | no | true | Apply 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_DIR | no | <cwd>/server/db/migrations | Override the migrations folder location |
NUXT_PUBLIC_REGISTRATION | no | open | Who may sign up themselves: open (anyone), invite (a valid invite link is required), closed (nobody). See registration modes |
NUXT_AUTH_RATE_LIMIT | no | 10 | Max 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_SECURE | no | true | Secure 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_HOST | no | — | SMTP server for outgoing mail. Mail is off until this and NUXT_MAIL_FROM are both set |
NUXT_SMTP_PORT | no | 465 when secure, else 587 | SMTP port |
NUXT_SMTP_USER | no | — | SMTP username; when unset the connection is unauthenticated |
NUXT_SMTP_PASS | no | — | SMTP password / app password |
NUXT_SMTP_SECURE | no | false | true = implicit TLS (usually port 465). Leave unset for STARTTLS on 587 |
NUXT_MAIL_FROM | no | — | From address, e.g. Tick <tick@example.com>. Required together with NUXT_SMTP_HOST for any mail to go out |
NUXT_DEMO_MODE | no | false | Public-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_MODE | no | false | Shows the dismissible "Demo — data resets nightly" banner in the app shell |
NITRO_HOST | no | 0.0.0.0 (image) | Bind address of the production server |
NITRO_PORT | no | 3000 | Port of the production server |
POSTGRES_PASSWORD | no | tick | docker-compose only: password for the bundled Postgres |
TICK_PORT | no | 3000 | docker-compose only: host port the app is published on |
TICK_IP | no | 0.0.0.0 | docker-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
| Script | What it does |
|---|---|
npm run dev | Dev server with hot reload |
npm run build | Production build to .output/ |
npm run typecheck | vue-tsc over app + server |
npm run db:push | Sync the Drizzle schema straight to the DB (development) |
npm run db:generate | Write a SQL migration from schema changes — commit the server/db/migrations output |
npm run db:seed | Demo org "Hollow Studio" with ~3 weeks of entries (login: mara@example.com / tick-demo). Re-running it wipes and recreates that org |