Migrate from Namespace runners without a cold cache
Teams that migrate from Namespace runners are almost never leaving because of the hardware, which is good, and almost always underestimate the same thing: Namespace is not only a label, it is a set of drop-in actions and a cache that behaves unlike any other cache in this market. The label change takes a minute and the cache change decides whether the migration reads as neutral or as a regression.

Start with what moves and what does not. The label moves: runs-on is one line and every destination has a size that matches. The workflow steps mostly move untouched, because they are ordinary steps.
Three things do not move, and each one is a real edit. The nscloud- actions have to be swapped back for the standard ones. The cache changes scope, from shared to branch-isolated, which is a behavior change with no error attached. And the remote Docker builders that were on by default stop existing, so a workflow that deleted its buildx setup has to get it back.
What a runner profile was carrying
Namespace attaches its features to a runner profile rather than to individual steps, which is why the label looks so short and the migration is longer than it looks. A job that reads runs-on: namespace-profile-default may be getting a cache volume, a git mirror, a container image cache and a remote Docker builder without any of those appearing in the workflow file.
The undo list below is therefore a list of things to look for in the profile as well as in the YAML. Work through it before you change the label, because after you change it the symptoms are all the same symptom: the job is slower and nothing failed.
| Namespace surface | What it did | Standard replacement | What changes |
|---|---|---|---|
namespace-profile-* label | Selected the profile and everything attached to it | A size label, for example latchkey-small | Features attached to the profile stop being implicit |
nscloud-checkout-action | A faster checkout using a git mirror | actions/checkout | Clone time returns to an ordinary shallow clone |
nscloud-cache-action | A cache volume, shared across branches | actions/cache with explicit keys | You now write keys, and restores obey branch scope |
| Remote Docker builders, on by default | A warm BuildKit builder beside the runner | docker/setup-buildx-action plus cache export | Layer cache is exported and imported per build |
| Unit-minute billing | Charged at max(vCPU, RAM divided by 2) per minute | A fixed per-size rate | Memory stops costing extra when cores sit idle |
The cache is the migration
This is the change most likely to make a migrated pipeline slower with nothing in the log to explain it. Namespace documents that its cache action does not support manual partitioning: entries are shared across everything using that runner profile, which includes the default branch and every feature branch at once. actions/cache is the opposite by design, restorable only from the branch that wrote the entry or from the default branch.
So a workflow that never thought about cache keys was quietly getting cross-branch hits, and on the other side it will not. The fix is not exotic, it is a prefix key and a restore-keys fallback, but it has to be written before the first run rather than discovered from a timing graph a week later. Write the keys so a new branch falls back to the default branch entry, and accept that the first run on a new dependency set is cold.
- uses: actions/cache@v4
with:
path: ~/.npm
key: npm-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
npm-${{ runner.os }}-
npm-Undo the nscloud actions
Two actions account for most of what a Namespace workflow looks like, and both have a plain equivalent. The checkout action used a git mirror to make cloning cheaper; actions/checkout at its default depth of one is the replacement, and on a large repository the difference is a few seconds rather than a minute. The cache action becomes actions/cache with the keys from the section above.
Grep for the prefix rather than for the two names, because the surface is wider than most people remember: entries such as a container image cache, a tool cache directory, a cache size hint and a flag that disables the remote builders all share it. Anything matching nscloud- is either an action to replace or a setting whose effect is about to disappear.
jobs:
test:
# before
# runs-on: namespace-profile-default
# after
runs-on: latchkey-small
steps:
# - uses: namespacelabs/nscloud-checkout-action@v8
- uses: actions/checkout@v5
# - uses: namespacelabs/nscloud-cache-action@v1
# with:
# cache: npm
- uses: actions/cache@v4
with:
path: ~/.npm
key: npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: npm-
- run: npm ci && npm testDocker builds lose a warm builder
Namespace runs remote Docker builders and has them on by default, which means a workflow may have deleted its docker/setup-buildx-action step because it stopped being necessary. That step has to come back, and with it the cache export and import that a warm builder made unnecessary.
Expect the first few builds to be slower than the last few on Namespace were, and expect the ordinary Docker failure modes to reappear along with them: a rate limit once every job pulls base images again rather than finding them warm, or a cache backend that refuses a reservation. If image builds are most of your minutes, price a destination that sells a real build cache rather than assuming the layer cache covers it.
What you are giving up, stated plainly
Three properties have no equivalent on a Linux-x86_64-only destination, and one of them is usually why the team chose Namespace. It publishes the widest platform range in this market: Linux AMD64 and arm64, Windows, macOS on Apple Silicon, and Linux running on Apple Silicon at a seven times multiplier. It sells the smallest machine anybody sells, 1 vCPU with 2 GB, where every fixed-size vendor floors at two cores.
It also publishes a concurrency ceiling you can plan against, 32, 64 or 160 Linux vCPUs by plan, and its Business plan allows jobs up to 24 hours where a GitHub-hosted job caps at six. If any of those is load-bearing for you, this is a partial migration at best, and the right shape is to move the plain Linux x64 jobs and leave the rest.
The pre-flight checklist
Six items. Two greps, two decisions and two things to write before the first run rather than after it.
- Labels. Grep for
runs-on:.*namespace-and list every job, including any on Windows, macOS or Apple Silicon that cannot move at all. - Actions. Grep for
nscloud-. Every hit is either an action to swap or a profile feature whose effect is about to go away silently. - Cache keys. Write them, with
restore-keysprefixes, before the cutover. This is the item that decides whether the migration feels neutral. - Cache size. Compare what you are caching against the destination allowance, 10 GB per repository on GitHub-hosted and 25 GB on Latchkey, and decide what stops being cached.
- Docker. Grep for
docker/build-push-actionand check whether a buildx setup step was removed. Put it back withcache-fromandcache-tobefore the first image build. - Concurrency. Namespace publishes a vCPU ceiling by plan and most destinations publish a job count instead. A wide matrix that fitted one may queue on the other.
What no run backs, and why
Nothing on this page was reproduced on a runner, and the reason is specific to it: the two behaviors that matter most, a cache shared across branches and a cache scoped to one, only differ on the second run of a second branch. A single job proves nothing, and a harness that ran the same workflow twice on two vendors would be measuring their hardware, not their cache semantics.
So the cache behavior here is quoted from the two vendors' own documentation rather than timed, and the label and action names are read from the Namespace GitHub Actions docs on 2026-09-21. The numbers you should trust least are any about how much slower your first post-migration run will be, which is why this page does not state one.
Frequently asked questions
What replaces nscloud-cache-action when I leave Namespace?
actions/cache with keys you write yourself, plus restore-keys prefixes. The behavior is not equivalent: Namespace documents that its cache is shared across everything using a runner profile and does not support manual partitioning, while actions/cache restores only from the writing branch or the default branch. Without prefix fallbacks, every new feature branch starts cold.Why is my pipeline slower after moving off Namespace?
nscloud-checkout-action was replaced by an ordinary clone, which is slower on a large repository. Check them in that order.Can I move all of my Namespace jobs to one destination?
What do I lose in job length and concurrency?
Related guides
References
- Namespace GitHub Actions docs: runner profiles, cache volumes and remote builders (verified 2026-09-21)
- Namespace pricing: unit minutes, plan pools, concurrency ceilings and rounding (verified 2026-09-21)
- GitHub Docs: dependency caching reference, branch scope, size limit and eviction (verified 2026-09-21)
- actions/checkout: the default fetch depth and what a shallow clone costs (verified 2026-09-21)
- GitHub Actions documentation