Skip to main content
When you sit down to write infrastructure for the first time with ubx, you don’t start with providers, backends, or environment configs. You start with a single block in a single file. The unit block is ubx’s fundamental primitive — it declares one cloud resource, gives it a name, and sets its attributes. Everything else in the language builds on top of this. Before you wire outputs into Helm charts, define multi-environment hierarchies, or author reusable components, you need to be comfortable with what a unit block looks like, how ubx validates it, and what it compiles to. That’s what this tutorial covers — and it’s deliberately small, because the goal is clarity, not completeness.

What you’ll learn

  • The anatomy of a .iac file
  • The unit block — the fundamental building block of ubx
  • How ubx validate type-checks your infrastructure without touching the cloud

Why this matters

ubx validate never contacts the cloud — it reads your .iac files and the locally cached provider schema only. This means you can type-check infrastructure changes in CI without cloud credentials, and catch errors before they reach a real environment. It’s the first command you’ll run on every change.

The source code

# A unit block declares a single cloud resource.
# "aws_s3_bucket_v2" is the Pulumi resource type name.
# "assets" is the label — how you'll reference this resource elsewhere.
unit "aws_s3_bucket_v2" "assets" {
  bucket = "my-assets-bucket"
}

How it works

1

ubx parses the .iac file

The lexer tokenises the file and the parser builds an AST. Block type unit, resource type aws_s3_bucket_v2, label assets, and attribute bucket are recorded.
2

The type checker validates the schema

ubx looks up aws_s3_bucket_v2 in the cached AWS provider schema (~/.ubx/schemas/aws.json). It confirms bucket is a valid string attribute. Unknown attributes produce a warning; missing required fields produce an error.
3

ubx reports the result

No errors, no warnings → ✓ valid. The cloud is never contacted. No credentials needed.

What ubx generates

// Generated by ubx — do not edit
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const assets = new aws.s3.BucketV2("assets", {
    bucket: "my-assets-bucket",
});

Common mistakes

Using a Terraform resource type name (aws_s3_bucket) instead of the Pulumi name (aws_s3_bucket_v2) results in a schema-not-found warning. Run ubx schema list --filter s3 to find the correct type name.
Resource type names follow Pulumi’s naming convention, which often differs slightly from Terraform’s. Use ubx docs aws_s3 --list to search for matching types in the cached schema without having to guess.

Run it

ubx validate   # type-checks without cloud credentials
ubx plan       # requires AWS credentials
ubx apply      # provisions the S3 bucket

What you learned

A unit block declares a single cloud resource with a type and a label
ubx validate type-checks your .iac files locally — no cloud credentials required
Project config lives in ubx.iac — name, runtime, backend, and stacks in one place

Next steps

Inputs and Outputs

Add typed variables and stack exports

unit block reference

Full unit block syntax and all supported meta-arguments