.ubx/state on your machine, invisible to teammates and lost if you lose the machine. For any real team or production workload, you need a remote backend. S3 is the most common choice for AWS-focused teams: it’s durable, versioned, access-controlled, and already part of your infrastructure. The backend "s3" block configures Pulumi’s state storage to use an S3 bucket, with a key path that can include ${stack} interpolation so each stack (dev, staging, prod) stores its state at a separate, non-overlapping path. Every team member who runs ubx apply reads and writes the same state file — no more “works on my machine” state divergence.
What you’ll learn
- How
backend "s3"configures Pulumi state storage in S3 - How
${stack}interpolation creates per-stack state isolation - What happens at validate time vs apply time for backend configuration
Why this matters
Remote state is not optional for teams or production. Without it, two team members can’t apply the same stack without corrupting each other’s state. With S3 backend, state is a shared, durable, versioned artifact — team members work from the same source of truth.
The source code
How it works
ubx translates the backend block to a Pulumi login command
When you run
ubx apply, ubx calls pulumi login s3://my-ubx-state before executing the Pulumi program. The key path is passed as the state file location. The ${stack} variable resolves to the current stack name (dev, staging, or prod).Each stack gets a separate, non-overlapping state path
key = "myapp/${stack}/pulumi.json" means dev and prod never share a state file. Running ubx apply --env prod writes to myapp/prod/pulumi.json; running ubx apply (default env) writes to myapp/dev/pulumi.json. No risk of one stack overwriting another’s state.ubx validate checks syntax only — no S3 access required
The backend block is syntax-validated at compile time. The S3 bucket is not contacted during
ubx validate or ubx plan — only during ubx apply when Pulumi actually needs to read and write state. This means validate and plan work without S3 credentials.What ubx generates
backend blocks produce no TypeScript/Python/Go code. They configure the Pulumi CLI’s login target before the generated program runs. The generated program itself is identical regardless of backend — only the state storage location changes.index.ts
Common mistakes
Run it
What you learned
backend "s3" stores Pulumi state in S3 — accessible to the whole team${stack} in the key path creates per-stack state isolationThe S3 bucket must exist before the first apply;
ubx validate doesn’t contact S3Next steps
Backend encryption with KMS
Encrypt state secrets with AWS KMS
backend block reference
Full backend block syntax for S3, GCS, and Azure Blob
Full runnable example: github.com/ubiquex/ubx-examples/39-backend-s3-state

