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

# Managing environments with Git branches

> orun uses Git branches as environment boundaries. Each node tracks one branch, and Service domain templates resolve the correct hostname per environment.

orun has no built-in concept of a named environment — instead, it uses Git branches. Each node tracks exactly one branch, and everything on that node derives its configuration from manifests on that branch. Promoting a change from staging to production is a standard Git merge. Creating an ephemeral environment is opening a new branch.

## How branches map to environments

When you run `orun bootstrap`, the node is configured with a `gitBranch` value in its Node manifest. From that point on, the node only reads manifests from that branch. Nodes on different branches are completely independent: they share no state, no communication channel, and no coordination mechanism.

```yaml theme={null}
# nodes/web-prod.yaml — tracks main
spec:
  gitBranch: main

# nodes/web-staging.yaml — tracks staging
spec:
  gitBranch: staging
```

<Note>
  The `gitBranch` field defaults to `main` when omitted. To track a different branch, set it explicitly in the Node manifest before running `orun bootstrap`.
</Note>

## Production vs. non-production

orun distinguishes two environment classes:

* **Production** — the primary environment, typically the node tracking `main`
* **Non-production** — all other environments: staging, feature branches, ephemeral worktrees

The domain resolver uses this classification to decide whether to use `ingress.domain.default` or the `ingress.domain.environment` template when building the service URL.

## Worktrees as ephemeral environments

Git worktrees let you check out a branch into a separate directory without affecting the main working tree. orun uses worktrees to scope resources for ephemeral environments.

When a node tracks a worktree named `feat-auth`, orun scopes that environment's resources with a dot-separated prefix — for example, `feat-auth.` — to prevent naming collisions with production or staging resources on the same host.

## Service domain templates

The `ingress.domain.environment` field in a Service manifest uses `$ENV` as a placeholder. At runtime, orun replaces `$ENV` with the environment suffix derived from the branch name or worktree name.

```yaml theme={null}
apiVersion: run.orcra.dev/v0alpha
kind: Service
metadata:
  name: hello-world
spec:
  deployment: hello-world
  ingress:
    domain:
      default: hello-world.orcra.dev
      environment: hello-world.$ENV.orcra.dev
    ssl: true
```

With this configuration:

| Branch / environment | Resolved domain                   |
| -------------------- | --------------------------------- |
| `main` (production)  | `hello-world.orcra.dev`           |
| `staging`            | `hello-world.staging.orcra.dev`   |
| `feat-auth` worktree | `hello-world.feat-auth.orcra.dev` |

The `ingress.domain.default` value is used for production nodes where no environment suffix applies. The `ingress.domain.environment` template is used for all other nodes.

## Branch-per-environment pattern

The recommended pattern is one branch per long-lived environment and short-lived branches for ephemeral feature environments:

<Steps>
  <Step title="Create a node manifest per environment">
    Write a separate Node manifest for each environment. Point each at the correct branch and host.

    ```text theme={null}
    nodes/
      web-prod.yaml      # gitBranch: main
      web-staging.yaml   # gitBranch: staging
      web-feat-auth.yaml # gitBranch: feat-auth
    ```
  </Step>

  <Step title="Bootstrap each node">
    Run `orun bootstrap` once per node manifest. After bootstrap, each node tracks its own branch independently.

    ```bash theme={null}
    orun bootstrap nodes/web-prod.yaml
    orun bootstrap nodes/web-staging.yaml
    ```
  </Step>

  <Step title="Deploy to staging by pushing to the staging branch">
    Merge or cherry-pick changes to `staging`. The staging node picks them up within one poll cycle (default `5s`) without any manual deploy step.

    ```bash theme={null}
    git checkout staging
    git merge feat-auth
    git push origin staging
    ```
  </Step>

  <Step title="Promote to production by merging to main">
    When staging looks good, merge to `main`. The production node reconciles automatically.

    ```bash theme={null}
    git checkout main
    git merge staging
    git push origin main
    ```
  </Step>
</Steps>

## Setting up multiple environments

<Tabs>
  <Tab title="Two environments (prod + staging)">
    ```yaml theme={null}
    # nodes/web-prod.yaml
    apiVersion: run.orcra.dev/v0alpha
    kind: Node
    metadata:
      name: web-prod
    spec:
      host: 203.0.113.10
      gitRepo: git@github.com:org/manifests.git
      gitBranch: main
    ```

    ```yaml theme={null}
    # nodes/web-staging.yaml
    apiVersion: run.orcra.dev/v0alpha
    kind: Node
    metadata:
      name: web-staging
    spec:
      host: 203.0.113.20
      gitRepo: git@github.com:org/manifests.git
      gitBranch: staging
    ```
  </Tab>

  <Tab title="Ephemeral feature environment">
    ```yaml theme={null}
    # nodes/web-feat-auth.yaml
    apiVersion: run.orcra.dev/v0alpha
    kind: Node
    metadata:
      name: web-feat-auth
    spec:
      host: 203.0.113.30
      gitRepo: git@github.com:org/manifests.git
      gitBranch: feat-auth
      pollInterval: 5s
    ```

    Delete the node manifest and deprovision the host when the feature branch is merged and the ephemeral environment is no longer needed.
  </Tab>
</Tabs>

<Tip>
  Name your nodes to match their environment (for example, `web-staging`, `web-prod`). Because node manifests are committed to the repository, the name appears in Git history and makes it easy to trace which host a configuration change targeted.
</Tip>

<Warning>
  Each node independently decides what to run based solely on the manifests in its branch. If you delete a Deployment manifest from `main` without first removing it from `staging`, the staging node continues running that container. Always review all branches before removing shared resources.
</Warning>

<CardGroup cols={2}>
  <Card title="How orun reconciles containers" icon="rotate" href="/concepts/how-it-works">
    Understand the pull-based reconciliation loop that drives every node.
  </Card>

  <Card title="Manifest repository structure" icon="folder" href="/concepts/manifest-repository">
    Reference for Node, Deployment, and Service manifest fields.
  </Card>
</CardGroup>
