Skip to main content
At scale, platform engineering is a multi-repo discipline. The networking team owns the VPC and subnets. The security team owns IAM roles and KMS keys. The platform team owns the EKS cluster. Each lives in its own repository, its own stack, its own apply pipeline. But application stacks need all of these — they need the VPC ID to place resources, the IAM role ARN to grant permissions, the cluster endpoint to deploy workloads. Without a mechanism for cross-repo output consumption, teams copy-paste values, hard-code ARNs, or maintain sprawling config files that drift out of date. The remote block solves this: it declares a dependency on another stack’s outputs, and @remotename.output_name references consume those outputs as Pending<T> values — always up-to-date, always type-checked, never copy-pasted.

What you’ll learn

  • How remote declares a cross-repo stack dependency
  • The @name.output reference syntax for consuming remote outputs
  • What ubx validate checks vs what requires the remote stack to exist

Why this matters

remote references compile to Pulumi StackReference objects — the same mechanism Pulumi uses natively for cross-stack communication. ubx wraps this with compile-time type checking: if the interface contract is declared (tutorial 35), referencing a non-existent output is a compile error, not a runtime surprise.

The source code

# @platform.vpc_id is a RemoteRef — always Pending<T>.
# Compiles to: platform.getOutput("vpc_id")
unit "aws_security_group" "app" {
  name        = "myapp-${input.env}-sg"
  description = "App tier security group"
  vpc_id      = @platform.vpc_id
}

unit "aws_rds_instance" "db" {
  engine                 = "postgres"
  instance_class         = "db.t3.micro"
  identifier             = "myapp-${input.env}"
  vpc_security_group_ids = [unit.aws_security_group.app.id]
}

How it works

1

remote compiles to a Pulumi StackReference

remote "platform" { source = "...", stack = "prod-networking" } compiles to new pulumi.StackReference("org/platform/prod-networking") in TypeScript. Pulumi’s StackReference reads the remote stack’s outputs from its state backend.
2

@name.output compiles to getOutput()

@platform.vpc_id compiles to platform.getOutput("vpc_id"), which returns a pulumi.Output<unknown>. ubx wraps this with the declared type from the interface contract (if present) for type-safe downstream use.
3

ubx validate checks syntax; the remote stack must exist for plan/apply

ubx validate confirms the remote block’s syntax and that @platform.xxx references are syntactically valid. It doesn’t contact the remote stack’s backend or verify its outputs exist. ubx plan and ubx apply require the remote stack to have been applied and its state to be accessible.

What ubx generates

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

const config = new pulumi.Config();
const env = config.get("env") || "prod";

// remote block → StackReference
const platform = new pulumi.StackReference(`myorg/platform/${env}-networking`);

// @platform.vpc_id → platform.getOutput("vpc_id")
const appSg = platform.getOutput("vpc_id").apply(vpcId =>
    new aws.ec2.SecurityGroup("app", {
        name: `myapp-${env}-sg`,
        description: "App tier security group",
        vpcId: vpcId as string,
    })
);

const db = appSg.apply(sg =>
    new aws.rds.Instance("db", {
        engine: "postgres",
        instanceClass: "db.t3.micro",
        identifier: `myapp-${env}`,
        vpcSecurityGroupIds: [sg.id],
    })
);

export const dbEndpoint = db.apply(d => d.endpoint);

Common mistakes

remote stack outputs are untyped by default — platform.getOutput("vpc_id") returns pulumi.Output<unknown>. Without an interface contract (tutorial 35), you get no compile-time check that vpc_id actually exists in the remote stack. Reference an output that doesn’t exist and you’ll get undefined at apply time, not a compile error. Add an interface contract to the remote stack for type safety.
The stack attribute supports string interpolation — stack = "${input.env}-networking" is valid and the standard pattern for environment-specific remote stack references. This ensures the right stack is referenced for each environment without duplicating the remote block.

Run it

ubx validate              # syntax check — does not contact remote stack
ubx plan                  # requires remote stack to be applied and accessible
ubx apply                 # reads remote outputs at apply time

What you learned

remote compiles to a Pulumi StackReference — outputs are consumed with @name.output
ubx validate checks syntax only; ubx plan requires the remote stack to exist and be accessible
Add an interface contract to the remote stack for compile-time type safety on output references

Next steps

interface contract validation

Declare typed output contracts for cross-stack safety

remote block reference

Full remote block syntax and options