Skip to main content

ActualBudget Common — Shared Application Configuration

ActualBudget_Common is the shared application layer for ActualBudget. It is not deployed on its own; instead it supplies the ActualBudget-specific configuration that both ActualBudget_GKE and ActualBudget_CloudRun build on, so the two platform variants behave identically where it matters. End users never configure this layer directly — it has no deployment UI inputs of its own — but understanding what it provides explains the defaults you see in the platform docs.

For the infrastructure that actually provisions and runs ActualBudget, see the platform guides (ActualBudget_GKE, ActualBudget_CloudRun) and the foundation guides (App_GKE, App_CloudRun, App_Common).


1. What this layer provides

AreaProvided by ActualBudget_CommonWhere it surfaces
Container imageThin-wraps the official actualbudget/actual-server image so the foundation builds/mirrors it into Artifact Registrycontainer_image output of the platform deployment
Version pinningApp-specific ACTUALBUDGET_VERSION build ARG; latest pins to 25.7.1Image tag in Artifact Registry
Database engineNone — budget data lives in SQLite files under /data (database_type = "NONE")§Database in the platform guides
Database bootstrapNone — no db-init job; the server initialises its own files on first bootn/a
Object storageDeclares the Cloud Storage storage bucket that backs /data on Cloud Runstorage_buckets output
Core settingsSets ACTUAL_PORT = 5006, ACTUAL_SERVER_FILES = /data/server-files, ACTUAL_USER_FILES = /data/user-filesApplication behaviour in the platform guides
Optional API keyWhen enable_api_key = true, generates a 32-char token in Secret Manager, injected as ACTUAL_TOKENsecret_ids output / Secret Manager
Health checksSupplies the default startup/liveness probe behaviour against /health§Observability in the platform guides

2. Secrets in Secret Manager

ActualBudget has no mandatory generated secrets. There is no database password, encryption key, or JWT secret — the server password is set interactively on the first-run onboarding screen, and per-budget end-to-end encryption is configured by the user in the client.

The only optional secret is an API token, gated behind enable_api_key (default false):

  • When enable_api_key = true, a 32-character random value is generated and stored in Secret Manager under secret-<prefix>-<app>-api-key (for example secret-<prefix>-actualbudget-api-key), and injected into the container as the ACTUAL_TOKEN secret environment variable via the foundation's module_secret_env_vars mechanism.
  • When enable_api_key = false (the default), no secret is created and the module's secret_ids map is empty.

The option exists for deployments that need a pre-provisioned credential for automation before (or instead of) interactive setup.

Retrieve the secret after deployment (only when enable_api_key = true):

# List secrets for this deployment (names include the resource prefix):
gcloud secrets list --project "$PROJECT" --filter="name~api-key"

# Read a secret version:
gcloud secrets versions access latest --secret=<secret-name> --project "$PROJECT"

See App_Common for the shared secret and workload-identity model.


3. Database engine and bootstrap

ActualBudget does not use an external database. Each budget is a SQLite file, and the server's own account/metadata state is also file-based — everything lives under /data. Consequently:

  • database_type = "NONE" — no Cloud SQL instance, database, or user is created.
  • There is no db-init job — the server creates its files on first boot; nothing has to be bootstrapped ahead of time.
  • No PostgreSQL extensions and no Redis are involved (enable_redis = false in the Cloud Run variant).

Because the databases are files on the persistent /data volume, durability is a function of the storage backend, not a managed database service (see §6). Custom initialization_jobs are accepted for data loading or migration tasks; none is provided by default.


4. Container image and entrypoint

ActualBudget uses a thin-wrapper Dockerfile — it does not add a custom entrypoint script and runs the upstream image's own startup unchanged:

ARG ACTUALBUDGET_VERSION=25.7.1
FROM actualbudget/actual-server:${ACTUALBUDGET_VERSION}
  • image_source = "custom" — set purely so the foundation builds the image into Artifact Registry via Cloud Build; no application code is layered on top.
  • App-specific build ARG — the Dockerfile reads ACTUALBUDGET_VERSION, not the generic APP_VERSION the foundation injects (and would force to latest). When application_version = "latest" the build pins to 25.7.1; otherwise the requested version passes straight through.
  • No entrypoint translation — ActualBudget needs no database wiring or URL rewriting at boot, so the upstream startup is used as-is.

5. Core application settings

ActualBudget_Common establishes the minimal environment the server needs to come up on first boot and write its state to the persistent volume:

  • ACTUAL_PORT = "5006" — the server's HTTP port, matching the module's container_port.
  • ACTUAL_SERVER_FILES = "/data/server-files" — server metadata and the account database.
  • ACTUAL_USER_FILES = "/data/user-files" — the per-budget sync files.
  • No boot-time credentials — the server password is set through the first-run onboarding screen; nothing further is configured at boot.

Platform-specific mounting of /data:

  • Cloud Run mounts the storage Cloud Storage bucket at /data via GCS FUSE (enable_gcs_storage_volume = true).
  • GKE with stateful_pvc_enabled = true mounts a block PVC at the same path and sets enable_gcs_storage_volume = false to avoid a double-mount.

6. Object storage

A single Cloud Storage bucket is declared here and provisioned by the foundation, which also grants the workload service account access:

  • name_suffix = "storage", storage class STANDARD, public_access_prevention = "enforced", location resolved to the deployment region.
  • On Cloud Run it backs /data via GCS FUSE, so it holds the SQLite budget databases, server files, and user files — the only copy of your budget data.

List it with:

gcloud storage buckets list --project "$PROJECT" --filter="name~actualbudget"

Note on storage type. SQLite prefers block storage with low-latency random I/O. The GCS FUSE mount is fine for single-user / light use on Cloud Run, but SQLite does not tolerate GCS FUSE under heavy concurrent write — for durable production storage prefer the GKE variant's block PVC (stateful_pvc_enabled = true).


7. Health probe behaviour

ActualBudget_Common's own probe defaults issue an HTTP GET /health, with no authentication — so the probes pass independent of onboarding state. (The ActualBudget_CloudRun and ActualBudget_GKE wrapper modules override this default to /, which the Node server also answers with 200 as soon as it is listening — so the effective, deployed probe path is /; this section describes Common's own default before that override.)

  • Startup probeinitial_delay = 15s, timeout = 5s, period = 10s, failure_threshold = 10.
  • Liveness probeinitial_delay = 30s, timeout = 5s, period = 30s, failure_threshold = 3.

For the ActualBudget-specific, user-facing configuration (variables by group, outputs, and how to explore each service from the Console and CLI), see the platform guides: ActualBudget_GKE and ActualBudget_CloudRun.