Configuration Reference
Grove projects are configured through a grove.toml file at the project root
and through environment variables. Configuration controls module discovery,
database connections, server settings, credential store behavior, and runtime
defaults. All settings have sensible defaults for local development.
Prerequisites: CLI Reference, Database Backends, Server.
What you'll learn: Every configuration option available in grove.toml and via environment variables, with defaults and examples.
Configuration File
The configuration file is named grove.toml and lives at the root of your project directory:
my-project/
grove.toml <-- project configuration
order/
actions.grove
customer/
actions.grove
Grove uses TOML syntax. If no grove.toml is found, default values are used for all settings.
Project Settings
project_id = "my-app"
| Key | Type | Default | Description |
project_id | String | required | The project identifier. Used as the first segment of every resource name and persisted in the deploy tarball so the platform knows which project a deploy belongs to. |
manzano init <name> writes project_id = "<name>". On the first successful manzano deploy, the CLI replaces this with the server-minted form project_id = "prj_<ksuid>" (preserving comments and formatting in the file). Subsequent deploys read that ID and use it to route the tarball to the correct project. See CLI Reference — deploy for the first-deploy flow.
project_id must match the pattern [A-Za-z0-9_]+. Lowercase names and server-minted prj_... IDs both pass.
Module Discovery
[modules]
paths = ["order", "customer", "shared/types"]
exclude = ["experimental"]
| Key | Type | Default | Description |
paths | List<String> | auto-discover | Explicit list of module directories (relative to project root) |
exclude | List<String> | [] | Directories to exclude from auto-discovery |
When paths is not set, Grove auto-discovers modules by scanning for directories containing .grove files.
Per-Module Configuration
[modules.order]
table_prefix = "shop_order"
[modules.customer]
table_prefix = "cust"
| Key | Type | Default | Description |
table_prefix | String | module name | Custom database table prefix for this module |
Database Settings
[database]
backend = "postgres"
connection = "postgres://grove:secret@localhost:5432/grovedb"
| Key | Type | Default | Description |
backend | String | none (required for db operations) | Database backend: sqlite, postgres, mysql, tidb |
connection | String | none (required for db operations) | Database connection string |
Connection Pool
[database.pool]
max_connections = 20
min_connections = 5
idle_timeout_seconds = 300
max_lifetime_seconds = 3600
acquire_timeout_seconds = 30
| Key | Type | Default | Description |
max_connections | Int | 10 | Maximum number of connections in the pool |
min_connections | Int | 1 | Minimum idle connections to maintain |
idle_timeout_seconds | Int | 600 | Close idle connections after this many seconds |
max_lifetime_seconds | Int | 3600 | Maximum lifetime of a connection in seconds |
acquire_timeout_seconds | Int | 30 | Timeout for acquiring a connection from the pool |
Server Settings
[server]
listen = "127.0.0.1:3000"
cors_origin = "http://localhost:5173"
read_timeout_ms = 30000
write_timeout_ms = 30000
max_body_size = 1048576
workers = 4
| Key | Type | Default | Description |
listen | String | "127.0.0.1:3000" | Address and port to bind to |
cors_origin | String | none | Allowed CORS origin (omit to disable CORS) |
read_timeout_ms | Int | 30000 | Request read timeout in milliseconds |
write_timeout_ms | Int | 30000 | Response write timeout in milliseconds |
max_body_size | Int | 1048576 | Maximum request body size in bytes (default 1 MB) |
workers | Int | CPU count | Number of server worker threads |
shutdown_timeout_seconds | Int | 30 | Graceful shutdown timeout in seconds |
Worker Settings
[worker]
concurrency = 10
poll_interval_ms = 1000
retry_max_attempts = 5
retry_initial_delay_ms = 1000
retry_max_delay_ms = 60000
retry_backoff_multiplier = 2.0
| Key | Type | Default | Description |
concurrency | Int | 10 | Maximum concurrent workflow/activity executions |
poll_interval_ms | Int | 1000 | How often to poll for new work, in milliseconds |
retry_max_attempts | Int | 5 | Maximum retry attempts for failed activities |
retry_initial_delay_ms | Int | 1000 | Initial retry delay in milliseconds |
retry_max_delay_ms | Int | 60000 | Maximum retry delay in milliseconds |
retry_backoff_multiplier | Float | 2.0 | Exponential backoff multiplier |
Credential Store Settings
[credentials]
backend = "file"
path = ".grove/credentials"
| Key | Type | Default | Description |
backend | String | "file" | Credential store backend: file or database |
path | String | ".grove/credentials" | File path for the file-based credential store |
When backend = "database", credentials are stored in the same database configured in [database].
Logging
[logging]
level = "info"
format = "json"
| Key | Type | Default | Description |
level | String | "warn" | Log level: error, warn, info, debug, trace |
format | String | "text" | Log format: text or json |
Testing
[testing]
timeout_seconds = 30
parallel = true
backend = "sqlite"
connection = ":memory:"
| Key | Type | Default | Description |
timeout_seconds | Int | 30 | Per-test timeout |
parallel | Bool | true | Run tests in parallel |
backend | String | none | Default database backend for tests |
connection | String | none | Default database connection for tests |
Environment Variables
All configuration values can be overridden by environment variables. Environment variables take precedence over grove.toml values.
Naming Convention
Environment variables follow the pattern GROVE_<SECTION>_<KEY> in uppercase, with dots and nesting replaced by underscores:
| grove.toml Key | Environment Variable |
project.name | GROVE_PROJECT_NAME |
database.backend | GROVE_DATABASE_BACKEND |
database.connection | GROVE_DATABASE_CONNECTION |
database.pool.max_connections | GROVE_DATABASE_POOL_MAX_CONNECTIONS |
server.listen | GROVE_LISTEN |
server.cors_origin | GROVE_CORS_ORIGIN |
server.workers | GROVE_WORKERS |
worker.concurrency | GROVE_WORKER_CONCURRENCY |
logging.level | GROVE_LOG_LEVEL |
Special Environment Variables
| Variable | Description |
GROVE_MASTER_KEY | Master encryption key for the credential store (base64-encoded, 256-bit) |
GROVE_ENV | Environment name: development, staging, production (affects defaults) |
GROVE_CONFIG | Path to a custom grove.toml file (overrides default discovery) |
Environment-Specific Defaults
When GROVE_ENV is set, certain defaults change:
| Setting | development | staging | production |
logging.level | "debug" | "info" | "warn" |
logging.format | "text" | "json" | "json" |
server.cors_origin | "*" | none | none |
database.pool.max_connections | 5 | 10 | 20 |
Full Example
[project]
name = "ecommerce"
version = "1.2.0"
[modules]
paths = ["order", "customer", "inventory", "shared/types"]
[modules.order]
table_prefix = "shop_order"
[database]
backend = "postgres"
connection = "postgres://grove:secret@localhost:5432/ecommerce"
[database.pool]
max_connections = 20
min_connections = 5
[server]
listen = "0.0.0.0:3000"
cors_origin = "https://app.example.com"
workers = 8
[worker]
concurrency = 20
retry_max_attempts = 10
[credentials]
backend = "database"
[logging]
level = "info"
format = "json"
[testing]
timeout_seconds = 60
backend = "sqlite"
connection = ":memory:"
Precedence Order
Configuration values are resolved in this order (highest priority first):
- Command-line flags (e.g.,
--listen, --backend)
- Environment variables (e.g.,
GROVE_LISTEN)
- grove.toml values
- Environment-specific defaults (based on
GROVE_ENV)
- Built-in defaults
See Also