Skip to main content
Mill needs PostgreSQL, an API image and a UI image. Use an existing PostgreSQL database or let Compose run one for you. The default Compose file runs only the API and UI; it needs three environment values. You do not need Git, Node.js, a package-registry token or a source build. The first public release is proposed as v1.0.1. Choose a release only after its GitHub release and both public images have been published.

1. Download the installation files

Choose a version from Mill releases. Download docker-compose.yml and .env.example from that release’s source tag into an empty directory. You can use your browser or these commands:
Keep these files together and run the remaining commands from this directory. Compose reads .env automatically; --env-file /path/to/your.env is available if you store it elsewhere. Image versions are already set in the release’s Compose file.

2. Set three environment values

Edit .env:
Use a dedicated PostgreSQL database with a user that can create and modify its tables. Supply the provider’s complete connection URL, including any required TLS parameters. Percent-encode special characters in a URL’s username or password. The database host must be reachable from the API container; localhost inside that container refers to the container itself. Generate MILL_SECRET with a password manager or openssl rand -hex 32. Keep it private and preserve it across upgrades and restores: Mill uses it to protect authentication data. Leave MILL_BASE_URL as shown for local use, or use your final HTTPS origin for remote access.

3. Start Mill

Compose pulls both versioned images and waits for the API and UI to become healthy. The API applies its packaged database migrations automatically. Open localhost:4321 and create your workspace, name, email and password. The first account becomes an administrator; there is no default login. The setup form closes after that first account is created. Check the running services and the complete UI-to-API path:
Continue with your first board and task. No GitHub login or npm token is needed to pull public release images. Only the UI publishes a host port; it forwards authentication, API and streaming MCP requests privately to the API. The API holds the database URL and application secret; the UI has neither.

Optional: run PostgreSQL with Compose

If you do not have a database, download docker-compose.postgres.yml from the same release:
Generate a separate database password with openssl rand -hex 32. Add POSTGRES_PASSWORD to .env and use the same value in DATABASE_URL:
Keep the existing MILL_SECRET and MILL_BASE_URL values. Start all three services with the optional overlay:
Use both -f options for subsequent commands on this installation. The overlay creates persistent PostgreSQL storage, waits for database readiness before starting the API, and publishes no database port. Use --project-name mill consistently so Compose reuses the same volume. down stops the containers and leaves the volume intact; down --volumes permanently removes it.

Host Mill with HTTPS

Set MILL_BASE_URL to the exact browser origin, for example https://tasks.example.com, and recreate the services using your installation’s Compose command. The default UI port binds to 127.0.0.1:4321, ready for a reverse proxy on the same host. For example, a Caddy configuration can use:
A proxy on the Compose network can use web:4322 instead. Preserve the public host, support streaming HTTP at /mcp, and do not cache /api, /mcp or OAuth responses. Keep the database and API private. To change the local port or bind address, edit the web service’s ports entry in Compose and keep MILL_BASE_URL aligned with the browser URL. The public origin is used for cookies, passkeys, links and OAuth. Set it correctly before people register passkeys; changing it later requires a recovery plan. Remote access requires HTTPS. Local HTTP OAuth works automatically only when MILL_BASE_URL is an exact loopback origin; no extra switch is needed.

Use a deployment platform

Images read runtime environment variables directly. A platform or secret manager can supply them without an .env file: Use your PostgreSQL instance’s connection URL as DATABASE_URL. Keep the API and UI at the same release version, and route the public HTTPS hostname to the UI. Optional email settings are covered in configuration.

Optional: pin images by digest

If your deployment policy requires immutable references, download mill-images.json from the matching GitHub release. Replace the two services’ image fields in Compose with its images.api and images.web values:
These are image references, not application environment variables. Keep both images from the same release and retain the manifest with your installation records.

Protect your installation

Take a first backup, keep an encrypted copy of the environment settings, and preserve the original MILL_SECRET. Before changing versions, read upgrades. Troubleshooting covers startup, authentication and connectivity issues. Source builds are for contributors; see package registry setup.

In the app

Team setup