Setup
This guide shows you how to set up Velocity for parallel Terraform and OpenTofu execution.
Prerequisites
- Stategraph running (see Deployment guide)
- Stategraph CLI installed (see CLI documentation)
- Terraform or OpenTofu installed
- A Terraform project to configure
Step 1: Create an API Key
- Open Stategraph at http://localhost:8080
- Log in (via local authentication or OAuth)
- Navigate to Settings
- In the API Keys section, click Create API Key
- Copy the generated token and set it as an environment variable:
export STATEGRAPH_API_KEY="<your-api-key>"
Step 2: Configure the CLI
Point the CLI at your Stategraph server:
export STATEGRAPH_API_BASE="http://localhost:8080"
List your tenants to get your tenant ID:
stategraph user tenants list
Output:
550e8400-e29b-41d4-a716-446655440000 my-org
You can set STATEGRAPH_TENANT_ID to avoid passing --tenant on every command:
export STATEGRAPH_TENANT_ID="550e8400-e29b-41d4-a716-446655440000"
Step 3: Navigate to Your Root Module
All Velocity commands run from the root of the Terraform module you want to manage:
cd /path/to/your/terraform/module
Step 4: Import Existing State (or Create a New One)
If you have existing Terraform state (in S3, GCS, Terraform Cloud, or any backend), pull it to a local file and import it into Stategraph. This is a one-time operation — after this, Velocity manages state through the CLI:
# Pull your current state to a local file
terraform state pull > terraform.tfstate
# Import it into Stategraph
# The state name must not already exist — this command creates it
stategraph import tf \
--tenant <tenant-id> \
--name <state-name> \
--var-file <path-to-var-file> \
--var key=value \
terraform.tfstate
Run stategraph import tf from the root module directory and pass the path to the state file. If your Terraform configuration uses variables, pass the same --var-file and --var flags you use when running terraform plan or terraform apply so that Stategraph correctly captures your variable definitions.
Replacing an existing state
By default, stategraph import tf refuses to overwrite a state that already exists — the name must be new. If you need to re-import on top of an existing state (for example, after a failed first import or when migrating a state between environments), pass --overwrite:
stategraph import tf --overwrite \
--tenant <tenant-id> \
--name <state-name> \
terraform.tfstate
This replaces the HCL and state data for that state in-place. Use it deliberately — the previous contents are gone after the import completes.
If you're starting fresh (no existing state), create an empty state instead:
stategraph states create --tenant <tenant-id> --name <state-name>
Adding workspaces
If you use Terraform workspaces to manage environment variants (e.g., staging, production), create additional states in the same group. When stategraph.json already exists in the directory, the group ID is read automatically:
# First state creates the group and writes stategraph.json
stategraph states create --tenant <tenant-id> --name my-state
# Additional workspaces join the same group
stategraph states create --tenant <tenant-id> --name my-state-staging --workspace staging
stategraph states create --tenant <tenant-id> --name my-state-prod --workspace production
Then pass --workspace when planning or applying:
stategraph tf plan --tenant <tenant-id> --workspace staging --out plan.json
stategraph tf apply plan.json
Stategraph rewrites terraform.workspace references in your HCL to the correct workspace value, so workspace-conditional logic works as expected.
Step 5: Plan and Apply
Once your state is set up, use Velocity to plan and apply changes:
# Plan changes
stategraph tf plan --tenant <tenant-id> --out plan.json
# Apply the plan
stategraph tf apply plan.json
Version Control stategraph.json
Velocity commands generate a stategraph.json file in your module directory. This file stores the group ID for your module. The CLI combines this group ID with the --workspace flag (defaulting to "default") to resolve the correct state at runtime. Commit this file to version control so your team shares the same Stategraph state binding:
git add stategraph.json
git commit -m "Add Stategraph configuration"
Usage
Velocity is used through the stategraph tf commands, which replace terraform plan and terraform apply:
# Plan changes
stategraph tf plan --tenant <tenant-id> --out plan.json
# Apply a plan
stategraph tf apply plan.json
# Plan across multiple states in a single transaction
stategraph tf mtx --tenant <tenant-id> --out plan.json ./networking ./compute ./application
Configuration
By default, Velocity uses tofu (OpenTofu) as the execution binary. Set the TF_CMD environment variable to use a different binary.
Plan Options
| Option | Description |
|---|---|
--tenant |
Tenant ID (required, or set STATEGRAPH_TENANT_ID) |
--out |
Output file for the plan (required) |
--state |
State ID (auto-discovered from stategraph.json if not set) |
--workspace |
Workspace name (default: "default") |
--var |
Set a variable (key=value, repeatable) |
--var-file |
Path to variable file |
--force |
Force a resource address into the plan, supports globs (e.g., data.*) |
--detailed-exitcode |
Return detailed exit code |
| Environment Variable | Description |
|---|---|
STATEGRAPH_TENANT_ID |
Tenant ID (alternative to --tenant flag) |
TF_CMD |
Path to Terraform/OpenTofu binary (default: tofu) |
Other CLI Commands
Lower-level transaction management is available via stategraph tx:
# Create a transaction manually
stategraph tx create --tenant <tenant-id>
# List transactions
stategraph tx list --tenant <tenant-id>
# Abort a transaction
stategraph tx abort --tx <tx-id>
# View transaction logs
stategraph tx logs list --tx <tx-id>
See Transaction Commands for the full CLI reference and API Reference for the REST API.