Configuration
The variables in .env.example, grouped by what they do, including both authentication modes and the settings that control who can register.
Browse documentation
On this page
Everything is configured with environment variables. pnpm run setup creates
.env from .env.example when it is missing. Edit the resulting file privately. The file in the repository is the source of truth and has
the same notes inline. Keep secrets in a secret manager or an untracked env
file, not in version control.
Database
| Variable | Default | Purpose |
|---|---|---|
DATABASE_URL |
postgresql://postgres:postgres@localhost:5432/finance |
Connection string for any standard PostgreSQL. docker compose up -d starts one that matches this default. |
In production, connect as a dedicated non-superuser role without BYPASSRLS.
Superusers skip row level security, and row level security is what keeps
companies apart at the database level.
Authentication
There are two modes. AUTH_MODE picks one, and Balsa won't silently fall
back to the other.
Better Auth (default)
AUTH_MODE=better-auth gives you email and password sign-in. Use it for
anything reachable over a network and for any install with more than one person.
| Variable | Purpose |
|---|---|
AUTH_MODE |
better-auth for email and password sign-in. |
BETTER_AUTH_SECRET |
Secret for signing sessions. At least 32 random bytes; openssl rand -base64 32 works. |
BETTER_AUTH_URL |
The app's canonical URL, such as http://localhost:3000 or your HTTPS origin. |
BETTER_AUTH_TRUSTED_ORIGINS |
Optional. Extra allowed origins, comma separated. This is the only way to add one. |
AUTH_ALLOW_SIGN_UP |
Optional. true opens registration; it's off in production unless you set it. Turn it on while people register, then remove it. |
AUTH_SIGN_UP_CODE |
Optional, but set it whenever sign-up is on and other people can reach the server. Registrations without the code are refused on the server. |
The sign-up code is the only thing standing between the public and your install.
A server-side hook checks it in constant time, regardless of what the sign-in
page does. It also protects LOCAL_OWNER_EMAIL: the first Better Auth account
registered with that address takes over the existing local owner and their
data. If sign-up is open with no code, whoever registers that address first
gets that data. In production, Balsa logs a warning at startup if sign-up
is on without a code.
Balsa doesn't send email, so there are no invitations or password-reset emails. The code controls who can register, and anyone registered can work in the install.
Disabled
AUTH_MODE=disabled removes the sign-in screen. It's meant for one person on a
machine they trust.
| Variable | Purpose |
|---|---|
AUTH_MODE |
disabled for a single-user local install with no sign-in. |
LOCAL_OWNER_EMAIL |
The owner's email. In disabled mode it's the identity everything runs as; in Better Auth mode, the account registered with it owns the original company and its data. |
LOCAL_OWNER_NAME |
Optional display name. Defaults to User. |
LOCAL_OWNER_ID |
Optional stable id. Defaults to local-owner. |
ALLOW_AUTH_DISABLED |
Must be true to run disabled mode in production. |
Disabled mode offers no protection. Put it behind a VPN, a reverse proxy, or some other network access control, and don't expose it to the internet.
Because LOCAL_OWNER_EMAIL identifies the owner in both modes, you can start
out privately with auth disabled and later switch the same install, with the
same data, to Better Auth.
Model provider
| Variable | Default | Purpose |
|---|---|---|
MODEL_PROVIDER |
openrouter |
openai or openrouter. |
MODEL_NAME |
auto |
Default model, shown in the composer as Auto. |
OPENAI_API_KEY |
none | Required when the provider is openai. |
OPENROUTER_API_KEY |
none | Required when the provider is openrouter. |
MODEL_OPTIONS |
none | Optional. Extra models for the composer, as comma-separated Label=id pairs. Auto always comes first. |
Application
| Variable | Purpose |
|---|---|
APP_SECRET |
Application signing secret. |
CRON_SECRET |
Bearer token for the scheduled reconciliation and calculation endpoints, checked in constant time. Set it before turning those jobs on. |
HEALTHCHECK_SECRET |
Bearer token for the health endpoint. Without it, production health checks return 404. |
DEFAULT_COMPANY_NAME |
Name for the company created on first setup. It doesn't affect companies added later from the account menu, and it's ignored if the owner has a COMPANIES list. |
COMPANIES |
Companies to create for the owner. See below. |
COMPANIES
A comma-separated list of Name or Name:CUR entries. Currency defaults to
USD.
COMPANIES=Acme Holdings:USD,Beta GmbH:EUR
The companies are created on the owner's first sign-in, and the first one is the default. Names added later are created at the next sign-in. Editing or removing an entry won't rename or delete anything. New company in the account menu does the same job by hand. See Companies and users.
File storage
| Variable | Default | Purpose |
|---|---|---|
FILE_STORAGE |
local |
Where uploaded source files are stored. |
FILE_STORAGE_PATH |
.data/files |
Directory for local files. Each company gets its own prefix. |
Keep this directory out of any web root, lock down its permissions, and back it up the way you would any financial records.
Link to this site
| Variable | Purpose |
|---|---|
NEXT_PUBLIC_SITE_URL |
Optional. URL of a public docs site. If set, the app header shows a How Balsa works link to it; if not, there's no link. |
This optional setting links the application to its documentation. Database and model-provider settings can also point at external services. Self-hosted storage does not imply that model interpretation runs locally.
Check configuration
Run pnpm run doctor after changes. It checks the selected provider, required
secrets, database, migrations and storage without printing secret values.
Restart the application after changing server configuration; rebuild when changing
public build-time values.
The full Docker Compose profile overrides the app container's database connection,
file-storage path and Better Auth URL for its bundled local services. Review the
Compose configuration as well as .env before adapting it to a different host.
See Operating an installation.