Skip to main content
The Strata registry is the right home for components that are stable, versioned, and shared broadly across an organisation. But not every component needs to go through a registry. A component under active development, a team-internal module not ready for wider distribution, or a component sourced from an open-source repository on GitHub — all of these are better served by direct git resolution. The git:: source prefix tells ubx to clone the specified repository, check out the specified ref, and compile the .iac files at the specified subdirectory path as the component’s body. Pin to an immutable ref — a tag or a full SHA — and ubx caches the clone after the first resolution, making subsequent validates fast and offline-capable. Use a branch name and ubx re-clones on every validate, always reflecting the branch’s current state.

What you’ll learn

  • The git:: URL syntax: clone URL, subdirectory path, and ?ref= for pinning
  • How immutable refs (tags, SHAs) enable caching; mutable refs (branches) always re-clone
  • How to self-reference the ubx-examples repo for a self-contained example

Why this matters

git:: sources give you the benefits of a registry — versioned, external, independently-maintained components — without requiring a registry server. A ?ref=v1.2.0 pin is as reproducible as a registry version, and a public GitHub repository is as accessible as any npm package.

The source code

# git:: source — ubx clones the repository, checks out the ref,
# and compiles the .iac files at the specified subdirectory.
#
# URL format: git::<clone-url>//<subdir>?ref=<tag-or-sha>
# Note the double slash // between the repo URL and the subdirectory.
#
# This example self-references ubx-examples to demonstrate a working
# git:: source without depending on an external component repo.
# In a real project, replace the URL with your component repository.
component "database" {
  source         = "git::https://github.com/ubiquex/ubx-examples//18-local-iac-component/components/rds?ref=main"
  identifier     = "myapp-${input.env}"
  instance_class = "db.t3.micro"
  engine_version = "15"
}

How it works

1

ubx parses and validates the git:: URL at compile time

The URL format is validated during parsing — the git:: prefix, the // subdirectory separator, and the ?ref= parameter are all checked syntactically. An invalid URL produces a compile error before any network request is made.
2

The repository is cloned at validate time

When you run ubx validate (or ubx plan/apply), ubx clones the repository to a local cache (~/.ubx/cache/git/), checks out the specified ref, and resolves the subdirectory path. The .iac files found there are compiled as the component’s body — identical to a local ./components/rds source.
3

Immutable refs are cached; mutable refs always re-clone

A tag (?ref=v1.2.0) or full SHA (?ref=abc123def) is immutable — once cloned, ubx uses the cache for all subsequent validates. A branch name (?ref=main) is mutable — ubx re-clones on every validate to pick up the latest commit. Use a tag or SHA for reproducible builds in CI.

What ubx generates

// Generated by ubx — do not edit
// The git:: source resolves to the same .iac component as tutorial 18.
// The generated code is identical — source type is transparent at codegen.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

class RdsComponent extends pulumi.ComponentResource {
    public readonly endpoint: pulumi.Output<string>;

    constructor(name: string, args: { identifier: string; instanceClass?: string; engineVersion?: string }, opts?: pulumi.ComponentResourceOptions) {
        super("ubx:component:Rds", name, {}, opts);
        const db = new aws.rds.Instance(`${name}-db`, {
            identifier: args.identifier,
            allocatedStorage: 20,
            engine: "postgres",
            engineVersion: args.engineVersion ?? "15",
            instanceClass: args.instanceClass ?? "db.t3.micro",
            username: "admin",
            password: "changeme",
            skipFinalSnapshot: true,
        }, { parent: this });
        this.endpoint = db.endpoint;
        this.registerOutputs({ endpoint: this.endpoint });
    }
}

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

const database = new RdsComponent("database", {
    identifier: `myapp-${env}`,
    instanceClass: "db.t3.micro",
    engineVersion: "15",
});

export const dbEndpoint = database.endpoint;

Common mistakes

The double slash // between the repository URL and the subdirectory path is required — git::https://github.com/org/repo/subdir is wrong; git::https://github.com/org/repo//subdir is correct. The // is the separator between clone URL and path, consistent with Terraform module source conventions.
For components your team maintains, prefer tags over branch names in ?ref=. A ?ref=main source re-clones on every validate and can break when the branch changes unexpectedly. A ?ref=v1.2.0 source is locked and cached — fast and reproducible across your whole team.

Run it

# Requires network access to clone github.com/ubiquex/ubx-examples
ubx validate          # clones the repo, compiles the component, validates
ubx validate --no-network  # uses cache if already cloned; fails if not cached
ubx plan              # requires AWS credentials

What you learned

git:: sources clone a repository and compile the .iac files at the specified subdirectory
Immutable refs (?ref=v1.2.0, ?ref=<sha>) are cached; mutable refs (?ref=main) re-clone every time
The generated code is identical to a local .iac component — source type is transparent at codegen

Next steps

Component cost limit

Enforce a monthly spend ceiling on a component

Registry component

Versioned components via the Strata registry