> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ubiquex.io/llms.txt
> Use this file to discover all available pages before exploring further.

# git:: Source Component

> Consume a component directly from a git repository — no registry required.

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

<Info>
  `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.
</Info>

***

## The source code

<CodeGroup>
  ```hcl main.iac theme={"theme":"css-variables"}
  # 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"
  }
  ```

  ```hcl inputs.iac theme={"theme":"css-variables"}
  input "env" {
    type    = "string"
    default = "dev"
  }
  ```

  ```hcl outputs.iac theme={"theme":"css-variables"}
  output "db_endpoint" {
    value = component.database.endpoint
  }
  ```

  ```hcl ubx.iac theme={"theme":"css-variables"}
  ubx {
    name    = "git-source-component"
    runtime = "typescript"
    stacks  = ["dev", "staging", "prod"]
  }

  backend "local" {
    path = ".ubx/state"
  }
  ```
</CodeGroup>

***

## How it works

<Steps>
  <Step title="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.
  </Step>

  <Step title="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.
  </Step>

  <Step title="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.
  </Step>
</Steps>

***

## What ubx generates

<CodeGroup>
  ```typescript index.ts theme={"theme":"css-variables"}
  // 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;
  ```

  ```python __main__.py theme={"theme":"css-variables"}
  # Generated by ubx — do not edit
  import pulumi
  import pulumi_aws as aws

  class RdsComponent(pulumi.ComponentResource):
      def __init__(self, name, args, opts=None):
          super().__init__("ubx:component:Rds", name, {}, opts)
          db = aws.rds.Instance(f"{name}-db",
              identifier=args["identifier"], allocated_storage=20,
              engine="postgres", engine_version=args.get("engine_version", "15"),
              instance_class=args.get("instance_class", "db.t3.micro"),
              username="admin", password="changeme", skip_final_snapshot=True,
              opts=pulumi.ResourceOptions(parent=self),
          )
          self.endpoint = db.endpoint
          self.register_outputs({"endpoint": self.endpoint})

  config = pulumi.Config()
  env = config.get("env") or "dev"
  database = RdsComponent("database", {"identifier": f"myapp-{env}", "instance_class": "db.t3.micro"})
  pulumi.export("db_endpoint", database.endpoint)
  ```

  ```go main.go theme={"theme":"css-variables"}
  // Generated by ubx — do not edit
  package main

  import (
      "github.com/pulumi/pulumi-aws/sdk/v6/go/aws/rds"
      "github.com/pulumi/pulumi/sdk/v3/go/pulumi"
      "github.com/pulumi/pulumi/sdk/v3/go/pulumi/config"
  )

  type RdsComponent struct {
      pulumi.ResourceState
      Endpoint pulumi.StringOutput
  }

  func NewRdsComponent(ctx *pulumi.Context, name, identifier, instanceClass, engineVersion string, opts ...pulumi.ResourceOption) (*RdsComponent, error) {
      comp := &RdsComponent{}
      if err := ctx.RegisterComponentResource("ubx:component:Rds", name, comp, opts...); err != nil { return nil, err }
      db, err := rds.NewInstance(ctx, name+"-db", &rds.InstanceArgs{
          Identifier: pulumi.String(identifier), AllocatedStorage: pulumi.Int(20),
          Engine: pulumi.String("postgres"), EngineVersion: pulumi.String(engineVersion),
          InstanceClass: pulumi.String(instanceClass), Username: pulumi.String("admin"),
          Password: pulumi.String("changeme"), SkipFinalSnapshot: pulumi.Bool(true),
      }, pulumi.Parent(comp))
      if err != nil { return nil, err }
      comp.Endpoint = db.Endpoint
      ctx.RegisterResourceOutputs(comp, pulumi.Map{"endpoint": comp.Endpoint})
      return comp, nil
  }

  func main() {
      pulumi.Run(func(ctx *pulumi.Context) error {
          cfg := config.New(ctx, "")
          env := cfg.Get("env")
          if env == "" { env = "dev" }
          db, err := NewRdsComponent(ctx, "database", "myapp-"+env, "db.t3.micro", "15")
          if err != nil { return err }
          ctx.Export("dbEndpoint", db.Endpoint)
          return nil
      })
  }
  ```
</CodeGroup>

***

## Common mistakes

<Warning>
  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.
</Warning>

<Tip>
  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.
</Tip>

***

## Run it

```bash theme={"theme":"css-variables"}
# 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

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

***

## Next steps

<CardGroup cols={2}>
  <Card title="Component cost limit" href="/v1/tutorials/24-component-cost-limit">
    Enforce a monthly spend ceiling on a component
  </Card>

  <Card title="Registry component" href="/v1/tutorials/22-registry-component-strata">
    Versioned components via the Strata registry
  </Card>
</CardGroup>

***

<Info>
  Full runnable example: [github.com/ubiquex/ubx-examples/23-git-source-component](https://github.com/ubiquex/ubx-examples/tree/main/23-git-source-component)
</Info>
