A polyrepo should not mean learning a new build process every time you open a repository. Keep the repository boundaries that suit your teams, but standardize how work runs inside them. That is our position: a shared task convention and remote caching belong in a polyrepo just as much as in a monorepo. AI coding agents make that consistency more useful.
Repository layout and task execution are separate decisions
A polyrepo spreads an organization's projects across separate Git repositories. That can be a sensible choice when ownership, access, or release schedules differ. Our case for a monorepo still stands when projects change together. Neither layout removes the need to build, lint, type-check, and test each project reliably.
Remote caching works at the task level. A build tool computes a key from the inputs it knows about, then either executes the task or restores a previous result. A repository with one application can benefit when a developer, CI runner, or agent would otherwise repeat that work. Nx supports adding caching to a single existing project, and Turborepo supports local and remote caching in single-package workspaces. You do not need to reorganize your source tree to use either.
Choose a standard your teams can actually maintain
For JavaScript and TypeScript repositories, choose Nx or Turborepo as the default and maintain one adoption template. Do not make every new repository choose again. Teams already using Gradle or Bazel can keep their native build systems: both have their own remote caching mechanisms, documented by Gradle and Bazel. A standard per ecosystem is more useful than adding a second runner solely to make every command look identical.
The organization-wide agreement should cover:
- Entry points. Document the commands for building and checking a repository, and use those commands in local development, CI, and agent instructions.
- Toolchains. Pin the runner, runtime, and package-manager versions; commit the lockfile and use reproducible dependency installs.
- Cache correctness. Declare the files, dependencies, configuration, environment, and generated outputs each cacheable task needs.
- Access. Decide who can read and write each repository's cache, and inject credentials through the existing secret store.
- Maintenance. Give the template an owner and roll out changes through reviewed updates. A template copied once will drift.
Make exceptions explicit. A tiny repository whose checks finish faster than a remote lookup may only need local caching. Standardize the decision and its ownership; do not introduce a build system with no measurable benefit.
AI agents benefit from the same task cache
An agent may inspect a project, run its checks, edit one file, run checks again, and hand the change to CI. If those steps all invoke the same runner, unchanged tasks can reuse earlier results. Fresh agent environments and CI runners can also read results produced elsewhere, provided the inputs and execution environment are compatible.
The model's reasoning and responses are not being cached here. This is caching the deterministic tools it calls. A source edit still invalidates tasks that depend on it. Ten agents doing ten different builds do not automatically create ten cache hits, and a task cache does not share agent memory or coordinate their changes.
Put the supported commands in the repository's contributor guide and agent instructions. For an Nx repository with the four targets below, that instruction can be this small:
Install dependencies with npm ci.
Run checks with npm exec -- nx run-many -t lint typecheck test build.
Use these targets so local work, agents, and CI share task definitions.
If a task needs new inputs or outputs, update its configuration.
Use the uncached command when diagnosing cache correctness.AI can help introduce those conventions across repositories. The configuration and CI checks make them dependable after the initial migration.
A practical Nx setup for each repository
Start with one existing npm project whose package.json has working build, lint, typecheck, and test scripts. Keep those scripts running the underlying tools. Initialize Nx using its adoption guide, choose the minimum setup, and commit the resulting configuration and lockfile. Nx recognizes the root project through the nx property added to package.json.
npx nx@latest initUse the installed version for subsequent commands and keep it aligned across local, agent, and CI environments. Merge the following into nx.json. This example assumes the build writes to dist/, checks run once and exit, and checks produce no files that need restoring:
{
"namedInputs": {
"default": [
"{projectRoot}/**/*",
{ "runtime": "node -p \"[process.version, process.platform, process.arch].join('-')\"" },
{ "env": "NODE_ENV" }
]
},
"targetDefaults": {
"build": { "cache": true, "outputs": ["{projectRoot}/dist"] },
"lint": { "cache": true, "outputs": [] },
"typecheck": { "cache": true, "outputs": [] },
"test": { "cache": true, "outputs": [] }
}
}Keep generated directories such as dist/ and .nx/ in .gitignore. Add any other environment variables that affect results to the inputs, and declare coverage reports or incremental compiler files as outputs if your checks produce them. This conservative input set can invalidate more work than necessary; narrow it only after verifying correctness. See our guide to Nx inputs and outputs for that step.
Create a Cachely workspace for this repository and issue a token. Following the Nx setup guide, inject these variables into the shell or CI job that runs Nx. The native Cachely connection requires Nx 20.8 or later:
export NX_SELF_HOSTED_REMOTE_CACHE_SERVER=https://remote.cachely.dev
export NX_SELF_HOSTED_REMOTE_CACHE_ACCESS_TOKEN='REPLACE_WITH_THIS_REPOSITORY_TOKEN'
npm exec -- nx run-many -t lint typecheck test buildUse the bare cache host; Nx appends the protocol path. Supply the real token through your secret store instead of committing it. The same command becomes the validation step in CI and in agent sessions. Calling the original tool directly bypasses this Nx task cache.
If your standard is Turborepo
Keep the same single-project layout. Install and pin Turbo as a development dependency, keep the underlying package scripts, and define their caching and outputs in turbo.json using the single-package guide. For Cachely, the connection and validation command are:
export TURBO_API=https://remote.cachely.dev
export TURBO_TOKEN='REPLACE_WITH_THIS_REPOSITORY_TOKEN'
export TURBO_TEAM='polyrepo'
npm exec -- turbo run lint typecheck test buildFollow the Turborepo setup guide for remote-hit verification. Cachely selects the workspace from the token; TURBO_TEAM is required by the CLI but does not create a separate cache boundary. Choose one runner for a repository and use it consistently.
Share results within a repository, with deliberate boundaries
Our default is one Cachely workspace per repository, with separate tokens for CI and developers or agent environments. A workspace is the cache boundary; a token controls access to it. This keeps repositories with different readers and writers separate while using the same managed service. See workspaces versus tokens for the details.
The expected reuse is between executions of the same repository: a developer's build, an agent's checks, and CI. Putting several repositories behind one service does not make their builds interchangeable. Matching task names are insufficient, different cache protocols do not share artifacts, and separate Cachely workspaces do not share entries. Do not combine workspaces just to chase cross-repository hits.
Give write access to trusted producers. Read-only access still allows downloading cached files and logs, so only provide it to jobs allowed to see those artifacts. Keep credentials out of untrusted fork jobs. An agent receives permissions according to its execution context, just like any other caller; automation alone is no reason to grant a write token.
Prove a remote hit before rolling the template out
Start with an empty local task cache and run the Nx build with a write-capable token. Clear the local cache again, remove the declared generated build output, and repeat without changing inputs. For a root project named web-app:
npm exec -- nx reset --only-cache
npm exec -- nx build web-app
npm exec -- nx reset --only-cache
# Remove only this project's generated dist/ directory before the next run.
npm exec -- nx build web-appConfirm Nx reports [remote cache] and restores dist/ without executing the build. A fast second run with a warm local cache proves only local reuse. Then change a build input and confirm the previous result is not reused; check an environment input as well. Compare restored output with an uncached build before adopting the template elsewhere.
Cache deterministic builds and checks. Deployments, publishing, and migrations must execute their side effects. Tests against changing external services or mutable databases need fresh execution unless that state is fully represented in their inputs. Measure time spent executing versus restoring tasks, including transfer time. Our remote-cache benchmark guide gives a repeatable experiment.
Our position: keep the boundaries, share the conventions
Remote caching does not give a polyrepo atomic changes across repositories, a global dependency graph, or coordinated releases. Shared libraries still need versioning and consumer updates. Those are real reasons to consider a monorepo; they are separate from reusing a completed build.
If separate repositories fit your organization, keep them. Choose a supported task runner for each ecosystem, maintain its configuration as a standard, and give developers, agents, and CI the same path to validated results. Cachely provides the remote cache for Nx, Lerna, Turborepo, Gradle, and Bazel. The repository count is not the prerequisite. Repeatable work is.