Skip to main content
A customer’s install provisioned cleanly in March. It’s November, and you need to reprovision it. By default, that reprovision clones your sandbox repo right then and applies whatever is at the configured branch today. Eight months of module changes, a bumped provider constraint, a repo that someone renamed: all of it lands on infrastructure that has been running fine, and none of it is what the install was built with. Sandbox builds close that gap. Nuon packages your sandbox into an immutable OCI artifact, the same mechanism already behind component builds, and installs provision from the artifact instead of reaching for Git.

Reprovision what you provisioned

An artifact is immutable and pinned to an app config version. A reprovision a year later applies the exact code that install was created with.

No Git at apply time

The install runner pulls the sandbox from the same registry it already pulls component artifacts from. Nothing in your customer’s account reaches GitHub or holds a Git credential.

No Terraform Registry either

Providers ship inside the artifact, so a provision doesn’t depend on registry.terraform.io being reachable.

Break it on your own time

A bad sandbox fails at build time, in your branch run, instead of part-way through a customer’s provision.

Get a sandbox build

1

Build the sandbox once

If your app template uses app branches, the next push builds it automatically. Otherwise hit Build sandbox on the app’s Sandbox tab.
2

Provision or reprovision

Any sandbox run for an install on that app config version now uses the artifact. The run’s logs say which source it used.
There is no configuration for any of this. Nothing in your app config changes, and nothing below is something you have to set up.

How the source is resolved

Every sandbox run (provision, reprovision, or deprovision) resolves where to get the code from before it runs anything: The lookup is per install, not per app. It keys off the app config version that install is pinned to, so two installs on different versions of your app provision from two different sandbox artifacts, each one the sandbox that shipped with its version. A missing artifact is never a failure. No build for that version, or an artifact that can’t be resolved, falls back to cloning Git exactly as before. Installs that predate your first sandbox build keep working untouched, and each install picks up an artifact as it moves onto a version that has a build behind it. This applies to Terraform and Pulumi sandboxes alike. The runner unpacks the artifact and works in that directory instead of a clone, and everything downstream is unchanged.

Where builds come from

A sandbox build is a record tied to one app config version and one sandbox config, executed by the Control Plane. It moves through queued → planning → building → active, or error, and streams logs the whole way. The artifact is pushed to your app’s OCI repository (the same one your component builds are pushed to), tagged with the build’s ID.

On every app branch run

If your app uses app branches, the building components and sandbox step builds the sandbox alongside your components. It appears as its own row in that step, next to each component, and links through to its logs. Which ref gets built: if your sandbox lives in the same repo as the app config being built, the build is pinned to that run’s commit SHA, so the sandbox and the components come from one commit. If the sandbox lives elsewhere, it uses the ref from your sandbox config.

On demand

The app’s Sandbox tab lists every build with its status, and Build sandbox runs one against your current config. Each build links to a detail page with its timeline and logs.
Useful for validating a sandbox change before you push it, and for apps that don’t use app branches.

Vendoring Terraform providers

Sandbox builds are what make provider vendoring possible for a sandbox at all. There’s no build step to vendor into otherwise. The build runs terraform providers mirror and ships the resulting filesystem mirror inside the artifact. The install runner finds it on unpack and initializes against it, so provisioning needs no Terraform Registry access. Pin terraform_version in your sandbox.toml so the build mirrors providers for the version that will actually run:
sandbox.toml
Together, the sandbox artifact and vendored providers take a provision from “needs GitHub and registry.terraform.io” to “pulls one more artifact from the registry it already pulls component artifacts from.” That is a much smaller ask of a customer with a restricted egress policy.

Troubleshooting

There’s no active build for the app config version that install is pinned to. An install on an older version has no artifact behind it until it moves to a version that does. Check the app’s Sandbox tab for which versions have builds, and the sandbox run’s logs for which source it chose.
Two reasons it’s skipped: the app has no sandbox config, or the run had no config changes and wasn’t forced. A run with nothing to build doesn’t build anything, sandbox included. Re-trigger the run with force, or build once from the Sandbox tab.
Open it from the Sandbox tab or from the branch run’s build step and read its logs. These are the same failures you’d otherwise hit mid-provision: an unresolvable module, a provider constraint that can’t be satisfied, or invalid Terraform. That is the point of catching them here.
Confirm the install is using an artifact (not a Git fallback), and that terraform_version in your sandbox.toml matches the version that runs so the mirror was built for the right CLI. Rebuild after setting or changing it.

See also