TraderMemos
Self-hosting

Configuration

Every TM_* environment variable the API reads, with defaults and what it controls.

All server configuration is environment variables with the TM_ prefix. Set them in the shell, in Compose environment:, or in api/.env for local development. Restart the API after changing any of them.

Core

VariableDefaultPurpose
TM_HTTP_PORT8080API listen port. PORT (Railway/Heroku style) is honored only when TM_HTTP_PORT is unset
TM_DATABASE_URL(unset → SQLite)Unified DB URL — sqlite:///data/tradermemos.db or postgres://user:pass@host:5432/db?sslmode=require. Setting it to an empty string is a startup error
TM_DB_PATHdata/tradermemos.dbLegacy SQLite path, used only when TM_DATABASE_URL is unset
TM_ATTACH_DIR(derived)Attachment/media disk root. Defaults to <db dir>/attachments for SQLite, data/attachments for Postgres — set it explicitly for Postgres
TM_DEFAULT_CURRENCYUSDDefault account currency
TM_LOG_LEVELinfoLog level (debug, info, warn, error)

Auth & security

VariableDefaultPurpose
TM_JWT_SECRETdev-insecure-change-meJWT signing key, minimum 32 characters. The server refuses to start on a known-weak value unless TM_ALLOW_INSECURE_JWT=true. Generate with openssl rand -hex 32
TM_ALLOW_INSECURE_JWTfalse (true in the bundled Compose for first-run convenience)Permits a weak/short JWT secret. Never enable on a public host
TM_ALLOW_REGISTRATIONfalseOpens POST /auth/register after the first-user setup. Off by default — only the owner exists unless you opt in
TM_CORS_ORIGINS(empty — CORS disabled)Comma-separated allowlist for split CDN + API deployments. Supports wildcard hosts like https://*.vercel.app. Leave empty for same-origin setups

Upload limits

VariableDefaultPurpose
TM_ATTACH_MAX_BYTES10485760 (10 MiB)Per-file cap for trade screenshots and note media
TM_IMPORT_MAX_BYTES10485760 (10 MiB)Cap for CSV/JSON import uploads
TM_OCR_MAX_BYTES10485760 (10 MiB)Cap for screenshot-scan images (falls back to the attachment cap if ≤ 0)

The bundled nginx allows client_max_body_size 20m. If you raise any cap above 20 MiB, raise the nginx value (and any upstream reverse proxy) too.

AI — screenshot scan & trade coach

These are defaults only: once you save AI settings in Settings → AI, the database values win. Keys are stored server-side and never sent to the browser. See AI features.

VariableDefaultPurpose
TM_OCR_ENABLEDfalseEnable screenshot fill extraction
TM_OCR_VISION_BASE_URLhttps://api.openai.com/v1OpenAI-compatible endpoint for vision
TM_OCR_VISION_API_KEY(empty)Vision API key
TM_OCR_VISION_MODELgpt-4o-miniVision model
TM_OCR_VISION_TIMEOUT_SEC90Vision request timeout in seconds
TM_COACH_ENABLEDfalseEnable the LLM trade coach
TM_COACH_BASE_URLhttps://api.openai.com/v1OpenAI-compatible endpoint for the coach
TM_COACH_API_KEY(empty)Coach API key
TM_COACH_MODELgpt-4o-miniCoach model

Market data

VariableDefaultPurpose
TM_MARKET_DATA_ENABLEDtrueEnable the market-data service
TM_MARKET_DATA_PROVIDERyahooProvider name
TM_MARKET_DATA_API_KEY(empty)Provider API key, if the provider needs one
TM_ECON_CALENDAR_ENABLEDtrueEnable the economic-events calendar feed
TM_ECON_CALENDAR_FEED_URL(built-in)Override the events feed URL
TM_ECON_CALENDAR_REFRESH_MIN60Minutes between feed refreshes

Sharing & background jobs

VariableDefaultPurpose
TM_SHARE_LINKS_ENABLEDfalseTurns on public share pages. Off by default — a share link makes part of the journal reachable without auth
TM_PUBLIC_WEB_URL(empty)Public web-app origin used when building share-link URLs. Leave empty when the API origin also serves the web app (the bundled nginx deployment)
TM_JOBS_ENABLEDtrueGlobal background-job switch. Disable on extra replicas so scheduled work runs on one instance only
TM_JOB_EXCURSION_INTERVAL_MIN360Minutes between MAE/MFE backfill passes (0 disables)
TM_JOB_EXCURSION_LIMIT10Trades attempted per backfill pass (0 disables)
TM_JOB_FLEX_SYNC_INTERVAL_MIN360Minutes between IBKR Flex auto-sync runs (0 disables)
TM_JOB_ALERTS_INTERVAL_MIN60Minutes between alert-rule evaluations (0 disables)
TM_ALERTS_ALLOW_PRIVATE_WEBHOOKSfalseAllow alert webhooks to target private/internal addresses (SSRF guard — leave off unless your webhook receiver is on your LAN)

Web build-time variables

The SPA is static — these are baked in at build time, not read by the server:

VariablePurpose
VITE_APIFixed API base (e.g. https://api.example.com/api/v1) compiled into the build. Leave empty to use relative /api/v1, or let users set the Server field at login

Compose-only variables

Read by docker compose from the root .env, never passed into containers:

VariableDefaultPurpose
DOCKERHUB_USERNAMEsinhong2011Docker Hub namespace for tradermemos-api / tradermemos-web images
TM_IMAGE_TAGlatestImage tag — pin a release like 0.1.6 in production

On this page