Setup

Cost analysis is off by default. It has two moving parts:

  1. A pricing service, shipped inside the server image, that prices each resource. The on switch is STATEGRAPH_COST_ENABLED: set it to true and capabilities.costs.enabled is true; leave it unset and cost analysis is off. The server reaches the pricing service at STATEGRAPH_PRICING_SERVICE_URL, which defaults to http://localhost:8090 — the bundled in-image service — so you only set it to point at an external pricing service.
  2. A price book, the cloud pricing data the service looks resources up in, loaded into a cloud_pricing PostgreSQL database. The service loads it automatically on first boot and refreshes it on a schedule, so you don't manage it by hand.

So enabling cost is one durable step: set STATEGRAPH_COST_ENABLED=true in your deployment's environment. Because it lives in your deployment config — not inside the running container — it survives redeploys, restarts, pod reschedules, and ECS task replacements.

Enable cost

Set STATEGRAPH_COST_ENABLED=true in your server container's environment, the same place your other STATEGRAPH_* variables live. The bundled pricing service runs in the same container as the server, so STATEGRAPH_PRICING_SERVICE_URL already defaults to http://localhost:8090 and you don't need to set it.

Docker Compose

Add it to your .env (or the server service's environment:):

STATEGRAPH_COST_ENABLED=true

Then recreate the container so it boots with the new environment:

docker compose up -d

Kubernetes and Amazon ECS

Set the same variable on the server/stategraph container — in your Helm values for Kubernetes, or the task definition's container environment for ECS — then roll out the change. Because it's part of the Deployment / Task Definition, every new pod or task comes up with cost on. See the Kubernetes and ECS guides for exactly where to put it.

What happens on first boot

When the server comes up with STATEGRAPH_COST_ENABLED=true, the pricing service starts automatically and, if the price book is empty, loads it into the cloud_pricing database. The first load downloads a large dataset (several hundred MB compressed, millions of prices), so allow a few minutes and make sure the database has room. This runs in the background — the server and UI are available immediately; cost surfaces fill in once the first load completes.

Verify

Confirm cost analysis is enabled:

curl -H "Authorization: Bearer $STATEGRAPH_API_KEY" \
  http://localhost:8080/api/v1/capabilities
{ "costs": { "enabled": true } }

If enabled is false, the server booted without STATEGRAPH_COST_ENABLED=true, and POST .../costs/calculate returns 503. Once enabled, produce the first estimate for a state with POST .../costs/calculate, or wait for the next scheduled run.

On first enable the price-book load runs in the background, so cost figures only appear once it finishes (a few minutes). The pricing service reports progress on a readiness endpoint — 200 once the price book is loaded, 503 while it is still loading — which also serves as a Kubernetes/ECS readiness probe:

docker compose exec server curl -fsS http://localhost:8090/readyz

The price book

The price book lives in the cloud_pricing database, separate from your main Stategraph database. The pricing service manages it for you:

  • Loaded on first boot when the table is empty (see above).
  • Refreshed automatically every 168 hours (weekly) by default. Override the cadence with PRICING_REFRESH_HOURS; set it to 0 to disable automatic refresh. Reloads happen in the background with an atomic swap, so cost analysis keeps serving the previous prices until the new data is ready.
  • Persisted in the database, so it survives restarts. Make sure cloud_pricing has durable storage — the bundled Compose stores it on the db volume; on Kubernetes or ECS, use a managed or volume-backed PostgreSQL. If the database is wiped, the service simply reloads the book on the next boot.

To force an out-of-band reload (for example after changing PRICING_DATA_URL), run the loader directly:

docker compose exec server load-pricing-data

Configuration

You only need the variables below to customize the setup — for example, putting the price book in a separate database, changing the refresh cadence, or mirroring the price-book download.

Variable Default Description
STATEGRAPH_COST_ENABLED false Master on/off switch for cost analysis. Set to true to enable; without it, cost analysis is disabled.
STATEGRAPH_PRICING_SERVICE_URL http://localhost:8090 Endpoint of the pricing service. Defaults to the bundled in-image service; set it only to point at an external pricing service.
PRICING_REFRESH_HOURS 168 How often the pricing service reloads the price book. 0 disables automatic refresh.
STATEGRAPH_PRICING_DEFAULT_REGION us-east-1 Region assumed when a resource does not specify one.
STATEGRAPH_COST_SCHEDULE_HOURS 24 How often per-state cost snapshots are recomputed on a schedule.
STATEGRAPH_COST_EVENT_DEBOUNCE_HOURS 6 Minimum gap before an apply triggers another recompute.
STATEGRAPH_COST_PRICING_CALL_TIMEOUT_SECONDS 30 Timeout for a single pricing-service call.
PRICING_DB_HOST / PRICING_DB_PORT server's database Host and port of the cloud_pricing database. Defaults match the bundled Compose database.
PRICING_DB_USER / PRICING_DB_PASSWORD server's database Credentials for the cloud_pricing database.
PRICING_DB_NAME cloud_pricing Name of the price-book database.
PRICING_DATA_URL Stategraph's hosted price book Override the price-book download source, such as your own mirror for air-gapped installs.

See Environment Variables for the full server configuration reference.

Air-Gapped Installs

If the server cannot reach the internet to download the price book, host the products.csv.gz file on a reachable URL or internal mirror and set PRICING_DATA_URL to it; the service uses it for both the first-boot load and scheduled refreshes. To keep the price book in a database separate from the server's, set the PRICING_DB_* variables to point the pricing service and loader at it.

Next Steps