Deployment
Grove is a single server process with the web app built in. It needs a persistent data directory, a secret key, and a way for your users to sign in. Everything else is configured in the app.
Grove is under active development. Releases can change the database schema and add or remove features, so back up the data directory before upgrading.
Requirements
- CPU and memory: searches read memory-mapped indices, so memory for the page cache keeps them fast; more cores speed up indexing and broad searches. Requirements grow with the amount of indexed code.
- Disk: room for a bare mirror of every repository plus its search index. Fast local storage helps.
- Network: outbound HTTPS to your code hosts (API and git), your OIDC provider and SMTP server if used.
- Binaries:
gitand universal-ctags (not Exuberant Ctags). The container image includes both.
Running the container
The image runs Grove as the unprivileged user grove (UID/GID 10001) with DATA_DIR=/data and ctags preconfigured. Grove listens on port 8080 unless you set PORT.
docker run -d --name grove \
-p 8080:8080 \
-v grove-data:/data \
-e SECRET_KEY="$(openssl rand -base64 32)" \
-e PUBLIC_URL=https://grove.example.com \
-e OIDC_PROVIDER_URL=https://accounts.google.com \
-e OIDC_CLIENT_ID=… \
-e OIDC_CLIENT_SECRET=… \
grove
Keep SECRET_KEY somewhere safe and pass the same value on every start; generating a new one on each start would make stored code host tokens unreadable. An --env-file works well for this.
Docker Compose with PostgreSQL
services:
grove:
image: grove
ports: ['8080:8080']
env_file: grove.env
environment:
DSN: postgres://grove:secret@db:5432/grove?sslmode=disable
volumes: ['grove-data:/data']
depends_on: [db]
db:
image: postgres:17
environment:
POSTGRES_USER: grove
POSTGRES_PASSWORD: secret
POSTGRES_DB: grove
volumes: ['pg-data:/var/lib/postgresql/data']
volumes:
grove-data:
pg-data:
First start
-
Start Grove and sign in once with your identity provider (or open it directly on a public or development instance).
-
Make that account a superuser from the server’s command line:
docker exec -it grove ./server createsuperuserIt asks for the account’s email or user ID. Superusers can promote others under Settings → Users.
-
Under Settings → Code hosts, add your GitHub, GitLab or Bitbucket connection. See Code hosts.
-
Watch repositories arrive under Settings → Repositories. Each one is cloned, indexed and then searchable.


Database
Grove keeps users, settings, saved searches and commit metadata in a database. Search indices always live in DATA_DIR.
- SQLite (default): a file at
$DATA_DIR/db.sqlite. Nothing to set up; a good fit for one server. - PostgreSQL: set
DSN=postgres://…. Create an empty database and a user that owns it; Grove creates and migrates the schema itself.
Migrations run automatically on startup.
Data directory
| Path | Contents |
|---|---|
repos/ |
bare git mirrors of every repository |
indices/ |
Zoekt search indices |
db.sqlite |
the database, when using SQLite |
extension-key.pem |
signing key for the self-updating browser extension |
Mirrors and indices can be rebuilt from the code hosts; the database and extension-key.pem can’t. Back those up.
Behind a reverse proxy
Terminate TLS at your proxy and forward to Grove’s port. Then:
- set
PUBLIC_URLto the externalhttps://origin; Grove ignoresX-Forwarded-Host, - set
COOKIE_SECURE=trueso session cookies are never sent over plain HTTP, - allow long requests: searches can take up to
SEARCH_TIMEOUT(40 seconds), result downloads up toEXPORT_TIMEOUT(60 seconds), - set
MCP_ALLOWED_ORIGINSto your origin.
If the proxy authenticates users, Grove can trust its headers instead of using OIDC; see proxy headers.
Monitoring
Grove exposes Prometheus metrics at /metrics, or on a separate listener when METRICS_PORT is set. Besides server, sync and indexing metrics, tracked saved searches with a metric label publish their result counts there. Settings → Stats shows index and disk usage in the app.
Logs go to stdout; use LOG_FORMAT=json for log collectors.
Restricting outbound traffic
Grove clones from the URLs your code hosts’ APIs report. For tighter deployments, allow outbound connections only to your code hosts, OIDC provider and SMTP server at the network level (firewall, egress proxy or a Kubernetes NetworkPolicy).
Next steps
- Configuration: every environment variable.
- Authentication: set up sign-in and API access.
- Code hosts: choose what gets indexed.