docker-compose.yml in the repo root that runs every service you need: the API backend, the Next.js frontend, Redis, and a local Postgres database. This page walks you through starting the stack for the first time, configuring your environment, and making the changes needed before running Waterline in production.
Services
The compose file starts four services by default:| Service | Host port | Description |
|---|---|---|
api | 8000 | FastAPI backend |
frontend | 3001 | Next.js frontend |
redis | 6379 | Session cache and progress results |
postgres | 5433 | Local Postgres (when BACKEND=postgres) |
http://localhost:3001 and the API is at http://localhost:8000. Interactive API docs are available at http://localhost:8000/docs.
Prerequisites
- Docker Desktop (or Docker Engine + Docker Compose plugin on Linux)
- A GitHub OAuth app — create one at github.com/settings/developers with the callback URL
http://localhost:8000/api/connect/github/callback - A Jira OAuth 2.0 app — create one at developer.atlassian.com (required even if you don’t plan to connect Jira right away)
- At least one LLM provider API key (Anthropic, OpenAI, or a local Ollama instance)
Starting Waterline
Create your environment file
Copy the example file to Or do it manually:Open
.env:.env and fill in your values. At minimum, set your LLM provider key, GitHub OAuth credentials, and Jira OAuth credentials. See Environment configuration below for a minimal working example.Start the stack
- make
- docker compose
Verify the services are healthy
In a second terminal, check that all containers are running:The
api and frontend containers wait for Redis and Postgres to pass their health checks before starting. If you see any container in an unhealthy or exited state, check the logs:Open the app
Navigate to http://localhost:3001. Sign in with GitHub to create your workspace.
Environment configuration
The API container reads.env at startup. Here is a minimal configuration for a local BACKEND=postgres deployment:
Database initialization
WhenBACKEND=postgres, the Postgres container runs the schema initialization script automatically the first time the postgres_data volume is created. You don’t need to run any SQL manually.
If you need to reset the database and start fresh:
ChromaDB persistence
Waterline uses ChromaDB to store vector embeddings for code symbols. By default, the API container writes the index to./chroma on your host, which persists across restarts.
For production deployments or setups with multiple API instances, use Chroma Cloud instead:
./chroma directory is ignored.
Common commands
| Command | Description |
|---|---|
make dev | Build images and start all services (foreground) |
make stop | Stop all containers, keep data volumes |
make logs | Tail API logs |
make test | Run unit and eval tests |
docker compose commands:
Production setup
The default compose configuration is designed for local development. Before running Waterline in production, make these changes:- Set
ENVIRONMENT=productionin your.envfile. - Use a strong
JWT_SECRET— generate one withopenssl rand -hex 32. - Change the default Postgres credentials — update
POSTGRES_USER,POSTGRES_PASSWORD, andDATABASE_URLto non-default values. - Remove host port bindings for internal services — don’t expose Postgres (5433) or Redis (6379) to the host network.
- Add a reverse proxy — put nginx or Traefik in front of the API (port 8000) and frontend (port 3001) containers and terminate TLS there.
- Update your OAuth callback URLs — replace
localhostwith your real domain inGITHUB_REDIRECT_URI,JIRA_REDIRECT_URI, andAPI_BASE_URL.
docker-compose.prod.yml override to apply production settings without modifying the base file:
GitHub webhooks in local development
GitHub needs to reach your API over the public internet to deliver webhook events. In local development, use a tunnel to expose port 8000:.env to use the ngrok HTTPS URL before connecting a repository:
The ngrok URL changes each time you restart the tunnel unless you have a paid ngrok account with a reserved domain. Update
.env and reconnect the repository if the URL changes.Troubleshooting
Port already in use If Docker reports a port conflict on startup, another process is already using port 8000, 3001, 6379, or 5433. Find and stop it, or change the host-side port mapping indocker-compose.yml (the first number in "8000:8000").
Container stays unhealthy
The api container waits for both Redis and Postgres to pass their health checks. If either stays unhealthy, check its logs:
docker compose logs api and look for a startup error. The most frequently missing values are JWT_SECRET (when BACKEND=postgres), an LLM provider key, or the GitHub/Jira OAuth credentials.
Frontend shows a blank page or API errors
Check that FRONTEND_URL and API_BASE_URL in your .env match the URLs you’re actually using. A mismatch causes CORS errors that prevent the frontend from reaching the API.