infractl
v0.3.2
Published
Declarative infrastructure CLI for GCP. Define your Cloud Run services, Cloud SQL databases, VMs, buckets, and secrets in YAML — infractl handles the rest.
Downloads
139
Maintainers
Readme
infractl
Declarative infrastructure for GCP. Define your service in a minimal YAML file — infractl up provisions and deploys everything with a single idempotent command.
# deploy/gcp/backend.prod.yaml — that's the whole config
projectId: my-project
region: us-central1
service:
name: my-apinpm install -g infractl
infractl up --env prod # One command. Everything provisioned and deployed.infractl up runs the full pipeline in order: project creation -> APIs -> Artifact Registry + service accounts + IAM -> cross-project Cloud SQL IAM -> secrets sync -> Workload Identity Federation -> buckets -> VMs -> deploy to Cloud Run. It is idempotent — safe to run every time.
Why infractl?
| Problem | infractl |
|---------|----------|
| Terraform/Pulumi are overkill for teams that just need Cloud Run + SQL + secrets | One YAML file, zero state files, zero HCL |
| Raw gcloud commands are 50+ lines of scripts across CI/CD pipelines | infractl up --env prod replaces all of them |
| No visibility — you deploy and pray | infractl status, logs, rollback from the same CLI |
| Setting up a new environment takes a full day | infractl up --env staging — everything in minutes |
| AI agents can't use your infra tools | AGENTS.md + skills = any LLM can read, understand, and integrate |
What it does
- Cloud Run — build Docker image, push to Artifact Registry, deploy, health check, rollback
- Cloud SQL — provision instances, databases, users; run migrations via Auth Proxy
- Compute Engine — declare VMs in YAML, create with firewall rules, SSH access
- Secret Manager — sync
.envvalues to GCP secrets, bind to Cloud Run - Cloud Storage — create and configure GCS buckets idempotently
- IAM — automatic least-privilege role bindings for runtime and deployer accounts
- Workload Identity Federation — GitHub Actions OIDC setup in one command
- Netlify — create sites and get site IDs for frontend deploys
- Operations —
status,logs,rollback,config validatewithout leaving the terminal
Everything is idempotent — safe to run multiple times. Everything is declarative — defined in YAML, not scripts.
Quick Start
1. Define your infrastructure
Create deploy/gcp/backend.dev.yaml with just three fields:
projectId: my-project-dev
region: us-central1
service:
name: my-apiThat is a complete, valid config. Smart defaults fill in everything else (see Smart Defaults below).
2. Bring it up
infractl up --env devThat's it. infractl up creates the project (if needed), enables APIs, sets up Artifact Registry, creates service accounts with least-privilege IAM, syncs secrets, configures WIF, provisions buckets and VMs, builds the Docker image, pushes it, and deploys to Cloud Run.
3. Verify
infractl status --env dev # Service URL, revision, health
infractl logs --env dev --tail # Stream logsFull-featured config
When you need more, the simplified schema keeps things concise:
projectId: my-project
region: us-central1
project:
billingAccount: ABC-123-DEF
organization: "123456789"
service:
name: my-api
secrets:
DB_PASSWORD: db-password # string shorthand (expands to { name, version: "latest" })
JWT_SECRET: jwt-secret
github: # top-level shortcut for WIF config
owner: my-org
repo: my-repo
cloudsql: # top-level Cloud SQL (no nesting under service)
instance: other-project:us-central1:my-db
database: my_db
storage:
buckets:
- name: my-uploads
location: us-central1Then run:
infractl up --env prodEverything is provisioned and deployed in one pass, including cross-project Cloud SQL IAM bindings.
Installation
# Global (recommended)
npm install -g infractl
# Run directly without installing
npx infractl --help
# As a dev dependency
npm install -D infractlCI/CD (GitHub Actions)
- name: Install infractl
run: npm install -g infractl
- name: Deploy
run: infractl up --env prodCommands
The up command
| Command | Description |
|---------|-------------|
| infractl up --env <name> | Single idempotent command: provisions everything and deploys |
infractl up runs the full pipeline: project creation, API enablement, Artifact Registry, service accounts, IAM bindings, cross-project Cloud SQL IAM, secrets sync, Workload Identity Federation, storage buckets, VMs, Docker build + push, Cloud Run deploy, and health check. Every step is idempotent.
Individual commands
You can also run steps individually when needed:
| Command | Description |
|---------|-------------|
| infractl provision --env <name> | Provision APIs, Artifact Registry, IAM, secrets, buckets |
| infractl deploy --env <name> | Build image, push, deploy to Cloud Run, health check |
| infractl doctor --env <name> | Validate gcloud, auth, and project access |
| infractl wif --env <name> | Configure Workload Identity Federation (GitHub Actions OIDC) |
Cloud SQL
| Command | Description |
|---------|-------------|
| infractl sql ensure --env <name> | Ensure instance, database(s), and user (idempotent) |
| infractl sql run <script> --env <name> | Run db:migrate, db:backup via Cloud SQL Auth Proxy |
| infractl sql run proxy --env <name> | Start proxy for local development |
| infractl proxy --env <name> | Shortcut for sql run proxy |
Compute Engine (VMs)
| Command | Description |
|---------|-------------|
| infractl vm ensure --env <name> | Provision VMs from config (idempotent) |
| infractl vm list --env <name> | List all VMs in the project |
| infractl vm describe <name> --env <name> | Show VM details |
| infractl vm start/stop <name> --env <name> | Start or stop a VM |
| infractl vm delete <name> --env <name> --confirm | Delete a VM |
| infractl vm ssh <name> --env <name> | SSH into a VM |
Operations
| Command | Description |
|---------|-------------|
| infractl status --env <name> | Service URL, revision, image, resources, health |
| infractl logs --env <name> [--tail] | View Cloud Run logs (real-time with --tail) |
| infractl rollback --env <name> | Roll back to previous Cloud Run revision |
| infractl config validate --env <name> | Validate YAML against schema |
Environment & Secrets
| Command | Description |
|---------|-------------|
| infractl env sync --env <name> --apply | Sync env vars to Cloud Run without rebuilding |
| infractl secrets sync --env <name> --apply | Sync .env values to Secret Manager |
Storage & Hosting
| Command | Description |
|---------|-------------|
| infractl bucket -c <config> | Ensure GCS buckets from config |
| infractl bucket --project <id> --name <n> | Create a standalone bucket |
| infractl site create --provider netlify --name <n> | Create a hosting site |
Project
| Command | Description |
|---------|-------------|
| infractl project create --project-id <id> | Create a GCP project |
| infractl project attach --env <name> | Adopt an existing project |
Common Options
| Option | Description |
|--------|-------------|
| --env <name> | Environment: dev, staging, prod (auto-resolves config and .env) |
| -c, --config <path> | Explicit YAML path (alternative to --env) |
| --dry-run | Preview without executing |
| --apply | Execute (for commands that default to dry-run) |
Environment Resolution
| --env value | Config file | .env file |
|---------------|-------------|-----------|
| dev / development | deploy/gcp/backend.dev.yaml | .env.development (fallback: .env.dev) |
| staging | deploy/gcp/backend.staging.yaml | .env.staging |
| prod / production | deploy/gcp/backend.prod.yaml | .env.production (fallback: .env.prod) |
Smart Defaults
infractl fills in sensible defaults so minimal configs just work. Given service.name: my-api and region: us-central1:
| Field | Default value |
|-------|---------------|
| artifact.location | region (e.g. us-central1) |
| artifact.repo | "app" |
| artifact.image.name | service.name (e.g. my-api) |
| service.runtime.account.name | "${service.name}-runtime" (e.g. my-api-runtime) |
| wif.pool.id | "github-pool" |
| wif.deploy.account.name | "${service.name}-deployer" (e.g. my-api-deployer) |
Secrets shorthand -- instead of the verbose object form, use a plain string:
# shorthand (expands automatically)
secrets:
DB_PASSWORD: db-password
# equivalent expanded form
secrets:
DB_PASSWORD: { name: db-password, version: "latest" }GitHub shortcut -- a top-level github block configures WIF without spelling out pool/provider details:
github:
owner: my-org
repo: my-repoTop-level cloudsql -- declare your database at the root level; infractl up handles cross-project IAM automatically:
cloudsql:
instance: other-project:us-central1:my-db
database: my_dbConfig Schema
infractl supports two schema versions. Both use the same core fields.
v2 (recommended)
apiVersion: infractl/v2
environment:
name: staging
type: staging # development | staging | productionFull field reference
projectId: string # GCP project ID (required)
region: string # GCP region (required)
artifact:
location: string # Artifact Registry location
repo: string # Repository name
image:
name: string # Image name
tag: string # Default tag (default: "bootstrap")
service:
name: string # Cloud Run service name (required)
port: number # Container port (default: 3000)
cpu: string # CPU (default: "1")
memory: string # Memory (default: "2Gi")
timeout: string # Request timeout (default: "300s")
concurrency: number # Max concurrent requests (default: 80)
maxInstances: number # Max instances (default: 10)
runtime:
account:
name: string # Runtime service account name
env: Record<string, string> # Runtime env vars
secrets: Record<string, {name, version}> # Secret Manager bindings
dockerfile: string # Custom Dockerfile path
healthCheck:
path: string # Health endpoint (default: "/api/v1/health")
cloudsql:
instance: string # Connection name (project:region:instance)
proxyPort: number # Proxy port (default: 5499)
tier: string # Machine tier (e.g. db-f1-micro)
version: string # DB version (e.g. POSTGRES_14)
database: string # Primary database name
databases: string[] # Additional databases
lifecycle:
preDeploy: string[] # Scripts before deploy
postDeploy: string[] # Scripts after deploy
wif:
pool: { id, display }
provider: { id, display }
deploy:
account: { name } # Deployer service account
github: { owner, repo, ref }
storage:
buckets:
- name: string # Globally unique (min 3 chars)
location: string
storageClass: string
uniformBucketLevelAccess: boolean # (default: true)
publicAccessPrevention: boolean # (default: true)
lifecycle:
deleteAfterDays: number
compute:
vms:
- name: string # VM name (required)
zone: string # Zone (required, e.g. us-central1-a)
machineType: string # Machine type (required, e.g. e2-standard-2)
bootDisk:
image: string # OS image (default: debian-cloud/debian-12)
sizeGb: number # Disk size (default: 20)
type: string # Disk type (default: pd-balanced)
networkTags: string[]
labels: Record<string, string>
serviceAccount: string # SA name (resolved to full email)
startupScript: string
metadata: Record<string, string>
preemptible: boolean # Spot instance (default: false)
firewallRules:
- name: string
allow: string # e.g. "tcp:80"
sourceRanges: string[]
targetTags: string[]Environment Variables
| Variable | Description |
|----------|-------------|
| INFRACTL_TIMEOUT_MS | gcloud command timeout in ms (default: 60000) |
| INFRACTL_DB_WORKSPACE | npm workspace for db scripts (e.g. @my-org/db) |
| NETLIFY_AUTH_TOKEN | Netlify API token |
| CLOUD_SQL_PROXY_BIN | Custom cloud-sql-proxy binary path |
CI/CD Integration
Replacing raw gcloud commands
| Manual | infractl |
|--------|----------|
| 50+ lines of gcloud commands | infractl up --env prod |
| gcloud run deploy ... | infractl deploy --env prod |
| gcloud services enable ... | infractl provision --env prod |
| gcloud iam service-accounts create ... | infractl provision --env prod |
| gcloud secrets create && versions add ... | infractl secrets sync --env prod --apply |
| gcloud sql instances create ... | infractl sql ensure --env prod |
| gcloud iam workload-identity-pools create ... | infractl wif --env prod |
GitHub Actions workflow
name: Deploy
on:
push:
branches: [main]
permissions:
contents: read
id-token: write
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- uses: google-github-actions/auth@v2
with:
workload_identity_provider: projects/${{ vars.GCP_PROJECT_NUMBER }}/locations/global/workloadIdentityPools/github-pool/providers/github
service_account: my-deployer@${{ vars.GCP_PROJECT_ID }}.iam.gserviceaccount.com
- uses: google-github-actions/setup-gcloud@v2
- name: Install infractl
run: npm install -g infractl
- name: Deploy
working-directory: packages/backend
run: infractl up --env prodFirst-time setup
With infractl up, first-time setup is a single command:
infractl up --env prodThis replaces what previously required six separate commands. If you need to run individual steps, they are still available (see Commands).
AI Agent Integration
infractl is designed to be used by AI agents. Two files make this possible:
- AGENTS.md — structured command reference, config contract, and setup steps that any LLM can parse
- CLAUDE.md — Claude Code-specific instructions with skill references
Install globally, point your agent at AGENTS.md, and it can provision and deploy without human intervention.
Architecture
src/
index.ts # CLI entry (commander.js)
exec.ts # Process execution (cross-spawn)
log.ts # Logging
config/ # Zod schemas + YAML loader
env/ # .env file parser
commands/ # One file per command domain
gcloud/ # gcloud CLI wrappers
cloudsql/ # Cloud SQL proxy utilitiesPrerequisites
- gcloud CLI installed and authenticated
- Docker for
infractl deploy - cloud-sql-proxy for
infractl sql run - Node.js >= 18
Troubleshooting
| Problem | Solution |
|---------|----------|
| Commands hang | Check gcloud auth login. Override timeout with INFRACTL_TIMEOUT_MS=120000 |
| Docker build fails | Check Dockerfile path. Disable fallback with --no-dockerfile-fallback |
| Cloud SQL proxy not found | Install cloud-sql-proxy or set CLOUD_SQL_PROXY_BIN |
| Secret errors on deploy | Run infractl secrets sync --env <name> --apply --require-all |
| Need to roll back | infractl rollback --env <name> |
License
MIT - Julio Rodriguez
