Skip to main content

Infrastructure as Code

RBS brings cloud provisioning into the same ecosystem as your build system. Define infrastructure in pure RBS DSL alongside your application code, with full compatibility with the Terraform provider ecosystem.

Why RBS for Infrastructure?

FeatureRBSTerraformPulumi
LanguageRBS DSL (Python-like)HCL (custom)TypeScript/Python/Go
Provider SupportTerraform providers (5000+)NativeTerraform + native
Build IntegrationNativeSeparate toolSeparate tool
HermeticYesNoNo
Single BinaryYesRequires CLIRequires SDK + CLI

Getting Started

1. Register a Provider

Create an infra.rbs file in your project:
# Register the AWS provider (downloaded and cached automatically)
infra.register_provider(
    name = "aws",
    source = "hashicorp/aws",
    version = "5.31.0",
)

# Configure provider settings
infra.provider_config(
    provider = "aws",
    config = {"region": "us-west-2"},
)

2. Define Resources

# Create resources using RBS DSL
vpc = infra.resource(
    name = "main_vpc",
    type = "aws_vpc",
    inputs = {
        "cidr_block": "10.0.0.0/16",
        "enable_dns_hostnames": True,
        "tags": {"Name": "my-vpc"},
    },
)

# Use native loops — no special syntax needed
for i in range(2):
    infra.resource(
        name = "public_subnet_" + str(i),
        type = "aws_subnet",
        inputs = {
            "vpc_id": ":main_vpc",  # Reference by name
            "cidr_block": "10.0." + str(i) + ".0/24",
            "availability_zone": "us-west-2" + ["a", "b"][i],
        },
    )

3. Plan Changes

rbs infra plan //...
Output:
🔍 Generating infrastructure plan...

Planned changes:
  + main_vpc (aws_vpc)
      + cidr_block: "10.0.0.0/16"
      + enable_dns_hostnames: true
      + tags.Name: "my-vpc"

  + public_subnet_0 (aws_subnet)
      + vpc_id: <computed from main_vpc>
      + cidr_block: "10.0.0.0/24"

  + public_subnet_1 (aws_subnet)
      + vpc_id: <computed from main_vpc>
      + cidr_block: "10.0.1.0/24"

Summary: 3 to create, 0 to update, 0 to delete
📄 Plan saved to: .rbs/infra/plans/default.plan.json

4. Apply Changes

rbs infra apply --auto-approve

Supported Providers

RBS uses the Terraform Plugin Protocol (v5/v6), giving you access to 5000+ providers:
# AWS
infra.register_provider(name = "aws", source = "hashicorp/aws", version = "5.31.0")

# Google Cloud
infra.register_provider(name = "google", source = "hashicorp/google", version = "5.0.0")

# Azure
infra.register_provider(name = "azurerm", source = "hashicorp/azurerm", version = "3.0.0")

# Kubernetes
infra.register_provider(name = "kubernetes", source = "hashicorp/kubernetes", version = "2.24.0")

# Helm
infra.register_provider(name = "helm", source = "hashicorp/helm", version = "2.12.0")

# Any Terraform provider!
infra.register_provider(name = "datadog", source = "DataDog/datadog", version = "3.30.0")
Providers are automatically downloaded from the Terraform registry, verified via SHA256, and cached in .rbs/infra/plugins/.

Resource References

Reference other resources using :name syntax:
vpc = infra.resource(
    name = "main_vpc",
    type = "aws_vpc",
    inputs = {"cidr_block": "10.0.0.0/16"},
)

subnet = infra.resource(
    name = "public_subnet",
    type = "aws_subnet",
    inputs = {
        "vpc_id": ":main_vpc",           # Reference by name
        "cidr_block": "10.0.1.0/24",
    },
)

security_group = infra.resource(
    name = "web_sg",
    type = "aws_security_group",
    inputs = {
        "vpc_id": ":main_vpc",
        "ingress": [{
            "from_port": 80, "to_port": 80, "protocol": "tcp",
            "cidr_blocks": ["0.0.0.0/0"],
        }],
    },
)

Workspaces (Multi-Environment)

Define workspaces for environment-specific values:
infra.workspace(
    name = "dev",
    variables = {"environment": "dev", "instance_count": 1, "instance_type": "t3.micro"},
)

infra.workspace(
    name = "staging",
    variables = {"environment": "staging", "instance_count": 2, "instance_type": "t3.small"},
)

infra.workspace(
    name = "prod",
    variables = {"environment": "prod", "instance_count": 5, "instance_type": "t3.medium"},
)

# Use workspace variables in resources
for i in range(int(infra.var("instance_count"))):
    infra.resource(
        name = "server_" + str(i),
        type = "aws_instance",
        inputs = {
            "instance_type": infra.var("instance_type"),
            "tags": {"Name": "web-" + infra.var("environment") + "-" + str(i)},
        },
    )
rbs infra plan --workspace=dev //...
rbs infra plan --workspace=prod //...
rbs infra apply --workspace=prod --auto-approve

Reusable Components

Create reusable infrastructure modules using functions:
def create_vpc_stack(name, cidr, azs):
    """Create a complete VPC with subnets."""
    vpc = infra.resource(
        name = name + "_vpc",
        type = "aws_vpc",
        inputs = {"cidr_block": cidr, "enable_dns_hostnames": True},
    )
    
    subnets = []
    for i, az in enumerate(azs):
        subnet = infra.resource(
            name = name + "_public_" + str(i),
            type = "aws_subnet",
            inputs = {
                "vpc_id": ":" + name + "_vpc",
                "cidr_block": cidr.replace(".0.0/16", "." + str(i) + ".0/24"),
                "availability_zone": az,
                "map_public_ip_on_launch": True,
            },
        )
        subnets.append(subnet)
    
    return infra.component(
        name = name,
        resources = [vpc] + subnets,
        outputs = {"vpc_id": ":" + name + "_vpc.id"},
    )

# Use the component
prod_network = create_vpc_stack("prod", "10.0.0.0/16", ["us-west-2a", "us-west-2b"])
staging_network = create_vpc_stack("staging", "10.1.0.0/16", ["us-west-2a", "us-west-2b"])

Cloud-Agnostic Abstractions

Define infrastructure once, deploy to any cloud:
# Cloud-agnostic compute
web_server = compute(
    name = "web",
    instance_type = "medium",       # Mapped to t3.medium on AWS, n1-standard-2 on GCP
    image = "ubuntu-22.04",         # Mapped to the correct AMI/image per provider
    public_ip = True,
    providers = ["aws"],            # Change to ["gcp"] to switch clouds
)

# Cloud-agnostic database
db = database(
    name = "app_db",
    engine = "postgres",
    version = "15",
    instance_type = "small",
    storage_gb = 50,
    multi_az = True,
)

# Cloud-agnostic storage
assets = storage(
    name = "app_assets",
    versioning = True,
    encryption = True,
)

Build Integration

Reference build outputs in infrastructure:
# In BUILD.rbs
oci_image(
    name = "app_image",
    binary = ":app",
    base = "ubuntu:22.04",
    tag = "my-app:latest",
)

# In infra.rbs — reference the built image
infra.resource(
    name = "app_task",
    type = "aws_ecs_task_definition",
    inputs = {
        "family": "app",
        "container_definitions": [{
            "name": "app",
            "image": "//app:app_image",  # Reference build target
            "memory": 512,
            "cpu": 256,
        }],
    },
)

Commands

CommandDescription
rbs infra planGenerate and save an execution plan.
rbs infra applyApply changes (uses saved plan if available).
rbs infra destroyDestroy all managed infrastructure.
rbs infra showDisplay current state.
rbs infra refreshUpdate state from actual infrastructure.
rbs infra importImport existing resources into state.
rbs infra outputShow output values.
rbs infra graphGenerate dependency graph (DOT format).

State Management

State files are stored per workspace in .rbs/infra/state/:
.rbs/infra/state/
├── default.state.json
├── dev.state.json
├── staging.state.json
└── prod.state.json

Migration from Terraform

Convert HCL to RBS DSL:
resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"
  tags = { Name = "web-server" }
}
Import existing resources:
rbs infra import aws_instance.web i-0abc123