Compare commits

...

131 Commits

Author SHA1 Message Date
Jesse Zomer d7c759cd17 fix(linter): allow for wildcards paths in enforce-module-boundaries rule (#34066)
closed #32190

## Current Behavior

eslint crashes when tsconfig.base.json path includes a * and you have an
import going to that project
## Expected Behavior
The plugin shouldn't crash and it should auto fix to a working import

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->
https://github.com/nrwl/nx/issues/32190

Fixes #32190

(cherry picked from commit ac2ef1aaef)
2026-02-26 16:35:14 -05:00
Jason Jean e941892573 chore(repo): update nx to 22.6.0-beta.5 (#34618)
Updating Nx from 22.6.0-beta.3 to 22.6.0-beta.5

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
(cherry picked from commit 191054d876)
2026-02-26 16:35:14 -05:00
Eric Baer 975dff72eb fix(testing): use surgical text replacement in Jest matcher alias migration (#34350)
## Current Behavior

The `replace-removed-matcher-aliases` migration uses `tsquery.replace()`
which reprints the entire AST through TypeScript's Printer. This causes
two problems:

1. **Syntax corruption**: Valid TypeScript files are mangled:
   - Destructuring patterns: `{ result }` becomes `{result}:`
   - Arrow functions: missing opening braces
   - Nested callbacks: collapsed/merged code blocks

2. **Unnecessary file changes**: Every test file is written back to disk
even when no matchers are replaced. This triggers `formatFiles()` to
reformat unchanged files, creating large whitespace-only diffs. In large
codebases, this can result in hundreds or thousands of files being
modified unnecessarily, making the migration PR difficult to review.

**Why I care a Lot**

I was running this on a multi-million-LOC monorepo and ran into two
issues:

* I got ~10k modified files with whitespace-only changes from the
removal of newlines. These changes couldn't be fixed with Prettier
because it didn't care about the number of newlines, so the diff was
unmergeable.
* I got ~8 files with malformed Typescript, causing commit hooks, CI,
etc. to fail without manual intervention.

## Expected Behavior

The migration should:
1. Only replace the deprecated matcher names (e.g., `toBeCalled` →
`toHaveBeenCalled`)
2. Preserve all surrounding code exactly as written
5. Only touch files that actually contain deprecated matchers

## Solution

Replace AST-reprinting with surgical text replacement:
- Use `tsquery.query()` to find matching AST nodes
- Collect text positions (start/end) for each node to replace
- Apply replacements in reverse order using string slicing
- Only write files that actually changed

This pattern is already used successfully in other Nx migrations (e.g.,
`rename-cy-exec-code-property.ts` in the Cypress package).

**Additional improvements:**
- Single AST parse with regex selector vs. 11 separate passes
- Quick string check skips parsing files without deprecated matchers
- New regression test covers complex patterns that triggered corruption

## Related Issue(s)

Fixes #32062

---------

Co-authored-by: Jack Hsu <jack.hsu@gmail.com>
(cherry picked from commit b8b6ed8b85)
2026-02-26 16:35:14 -05:00
Jason Jean f3cfed2b01 chore(repo): improve e2e test timeout handling and bump cache bust (#34383)
## Current Behavior

E2E tests may timeout without clear error messages, making it difficult
to diagnose test failures.

## Expected Behavior

E2E test utilities should provide better timeout handling and logging to
help diagnose test failures.

## Changes

- Add timeout handling to e2e test utilities (`runCLI` and
`runLernaCLI`)
- Add command logging to track execution time
- Improve timeout error messages with process output
- Bump cache bust value

## Related Issue(s)

CI stability and debugging improvements

(cherry picked from commit bdc61b5ad5)
2026-02-26 16:35:14 -05:00
Jason Weinzierl d54acd9240 fix(linter): support eslint v10 (#34534)
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior

`@nx/eslint` relies on ESLint internals that changed in ESLint v10
(`use-at-your-own-risk`), which causes failures.

It looks like https://github.com/nrwl/nx/pull/24632 originally attempted
to use `loadESLint()` which would've been forward compatible with v10,
but it was later removed in https://github.com/nrwl/nx/pull/27404 in
favor of the `use-at-your-own-risk` import.

## Expected Behavior

`@nx/eslint` supports ESLint v10.

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #34415

(cherry picked from commit 31dad4109b)
2026-02-26 16:35:14 -05:00
omasakun 0adf2f4e3b fix(core): make watch command work with all and initialRun specified (#32282)
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

If you specify both the `all` and `initialRun` options when running `nx
watch`, `initialRun` have no effect.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

The command should be called once at the beginning even if there are no
file changes.

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #32281

(cherry picked from commit c3643126ef)
2026-02-26 16:35:14 -05:00
Anurag Agarwal fe3c51c7ac fix(maven): fix set the pom file without changing base directory (#34182)
## Current Behavior
nx-maven-plugin 0.0.12 is also changing the base directory along with
the pom file when the plugins like flatten-maven-plugin /
maven-shade-plugin produces pomFile in different directory other than
the base directory

## Expected Behavior
plugin should only update the pom file and not the base directory
location

## Related Issue(s)

Fixes #34181

https://github.com/mojohaus/flatten-maven-plugin/issues/50

Co-authored-by: anurag.ag <anuragagarwal561994@users.noreply.github.com>
(cherry picked from commit dcfc2134d4)
2026-02-26 16:35:14 -05:00
Jack Hsu 27e2a59822 docs(misc): add Requirements sections to all technology intro pages (#34613)
## Current Behavior

Technology introduction pages have inconsistent or missing version
requirements information. Some pages have no Requirements section,
others use ad-hoc formats (asides, bullet lists under Prerequisites),
and page titles follow different naming conventions ("Overview of the Nx
X Plugin", "Nx X Plugin Overview", "Introduction - X", etc.).

## Expected Behavior

Every technology introduction page now has a standardized Requirements
section with:
- A version support table using consistent semver range format
- Code-formatted package names in the `Package` column
- An intro sentence identifying the Nx plugin (e.g. "The `@nx/react`
plugin supports the following package versions.")
- A note linking to [code generation docs](/docs/features/generate-code)
for auto-installed packages
- Consistent **"X Plugin for Nx"** page title pattern across all intro
pages

Additional changes:
- Deleted the standalone Node.js/TypeScript compatibility page, inlining
its content into the respective plugin intro pages
- Created a proper introduction page for Angular Rsbuild (previously
linked directly to `createConfig` API reference)
- Added Requirements tables to Java, Gradle, and Maven pages with system
dependency versions
- Updated sidebar links and redirects for removed/moved pages
- Applied style guide fixes across all edited pages (removed "allows you
to", "easily", product possessives, etc.)

## Related Issue(s)

Fixes DOC-423

(cherry picked from commit 77100fac5d)
2026-02-26 16:35:13 -05:00
Caleb Ukle 6f9fa14f9f docs(nx-plugin): document special schema options (#34615)
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: barbados-clemens <barbados-clemens@users.noreply.github.com>
(cherry picked from commit 0ae45cd445)
2026-02-26 16:35:13 -05:00
Jason Jean 2af413b755 fix(core): preserve nxCloud=skip in non-interactive CNW mode (#34616)
## Current Behavior

After #34580, `determineNxCloudV2()` returns `'skip'` in non-interactive
mode, but the caller remaps it to `nxCloud = 'yes'` with
`skipCloudConnect = true`. This causes `setupCI()` to run and generate
`.github/workflows/ci.yml` in new workspaces — which didn't happen
before.

This breaks the `extras.test.ts` e2e snapshot test because
`.github/workflows/ci.yml` now appears in the expanded default task
inputs.

## Expected Behavior

Keep `nxCloud = 'skip'` when the cloud choice is `'skip'`, which
prevents CI file generation in non-interactive mode. This restores the
behavior prior to #34580.

## Related Issue(s)

Fixes the `extras.test.ts` e2e snapshot failure introduced by #34580.

(cherry picked from commit fcf4660389)
2026-02-26 16:35:13 -05:00
Louie Weng a13598d782 chore(gradle): bump version to 0.1.13 (#34614)
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

Bump project graph plugin version.

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
(cherry picked from commit 221ea40462)
2026-02-26 16:35:13 -05:00
Leosvel Pérez Espinosa 32e3d7e30c cleanup(core): cache compiled glob sets to avoid redundant recompilation (#34602)
## Current Behavior

`build_glob_set` recompiles identical glob pattern sets on every call,
even when the same set of patterns has been compiled before.

## Expected Behavior

Compiled `NxGlobSet` instances are cached in a static `DashMap` keyed by
sorted glob strings. Repeated calls with the same patterns return a
shared `Arc<NxGlobSet>` instead of recompiling. Profiling `nx run-many
-t build lint test --parallel 8` in the Nx repo measured 95.6% cache hit
rate (9,758 of 10,202 calls) with only 444 unique pattern sets, reducing
hashing-phase CPU by ~40%.

(cherry picked from commit 12812dc994)
2026-02-26 16:35:13 -05:00
Jack Hsu f1d444e0dc fix(nx-dev): move redirects from Next.js config to Netlify _redirects (#34612)
## Current Behavior

All 1,200+ redirect rules are processed by the Next.js serverless
function via the `redirects()` config in `next.config.js`. Every
redirect request requires a cold start of the serverless function, which
contributed to the 10-minute outage reported in DOC-415.

## Expected Behavior

Redirects are handled at the Netlify CDN edge via a plain `_redirects`
file, which is faster and doesn't depend on the Next.js serverless
function being healthy.

- Converted all redirect rules from `redirect-rules.js` and
`redirect-rules-docs-to-astro.js` into Netlify `_redirects` format
(1,231 rules)
- Expanded Next.js regex group patterns (e.g. `/(l|latest)/...`) into
individual Netlify rules since Netlify doesn't support regex
- Converted `:path*` wildcards to Netlify `*`/`:splat` syntax
- Rewrites (Astro docs proxy) remain in `next.config.js` as they require
server-side processing
- Original JS redirect files kept for reference (can be removed in
follow-up)

## Related Issue(s)

Fixes DOC-415

(cherry picked from commit 4c3812f731)
2026-02-26 16:35:13 -05:00
Leosvel Pérez Espinosa c16dacda0d fix(core): use scoped cache key for unresolved npm imports in TargetProjectLocator (#34605)
## Current Behavior

`TargetProjectLocator.findProjectFromImport` stores `null` for
unresolved imports using a bare `importExpr` key, but
`findNpmProjectFromImport` looks up cache entries using
`${packageName}__${dirPath}`. The key mismatch means repeated lookups
for the same import+directory re-run the full resolution waterfall
(typescript + require.resolve) instead of returning the cached `null`.

## Expected Behavior

Store `null` for unresolved imports using the same
`${packageName}__${dirPath}` key that `findNpmProjectFromImport` uses
for lookups. Repeated lookups for already-failed imports skip the
expensive resolution steps.

Also removes an unused cache write for builtin module imports as a minor
cleanup.

(cherry picked from commit 098a830e5d)
2026-02-26 16:35:13 -05:00
Jason Jean f17d00e95b fix(core): handle FORCE_COLOR=0 with picocolors (#34520)
## Current Behavior

After migrating from chalk to picocolors (#34305), `FORCE_COLOR=0` no
longer disables colors. picocolors checks `!!env.FORCE_COLOR`, and since
`!!"0"` is `true` in JavaScript, it treats `FORCE_COLOR=0` as "enable
colors."

This breaks CI environments and tools like Homebrew that set
`FORCE_COLOR=0` to get plain text output.

## Expected Behavior

`FORCE_COLOR=0` should disable ANSI color output, matching the previous
chalk behavior and the [FORCE_COLOR spec](https://force-color.org/).

## Related Issue(s)

Fixes #34387

Upstream issue filed:
https://github.com/alexeyraspopov/picocolors/issues/100

(cherry picked from commit f31e7a75be)
2026-02-26 16:35:13 -05:00
Louie Weng d3ff96456a fix(gradle): use globs for dependent task output files (#34590)
## Current Behavior

When processing Gradle tasks, Nx tracks dependent task output files by
recording individual file paths for each output. This can lead to
incorrect cache invalidation behavior since we are prefixing the paths
unnecessarily. We will therefore never match.

## Expected Behavior

Nx now consolidates dependent task output files using glob patterns
based on file extensions (e.g., **/*.jar, **/*.class). This focuses on
the types of files produced rather than their specific paths. The
approach groups all output files by extension and generates a single
glob pattern per extension, reducing the complexity of input tracking
while maintaining correctness.

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #Q-247

(cherry picked from commit 09c44a637a)
2026-02-26 16:35:13 -05:00
Louie Weng ff7088ff5f fix(gradle): ensure that atomized task targets have dependsOn (#34611)
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

The dependsOn of atomized tasks should match the base non-atomized task.

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes Q-174

(cherry picked from commit dc81b8bbd6)
2026-02-26 16:35:12 -05:00
Jack Hsu 32155a1511 feat(core): add explicit cloud opt-out to CNW (#34580)
## Current Behavior

The CNW cloud prompt is locked to auto-select deferred connection
(CLOUD-4255), always generating a short URL but never writing nxCloudId
to nx.json. Users have no explicit choice.

## Expected Behavior

The cloud prompt now offers three explicit choices:
- Yes: connect now, generate nxCloudId in nx.json, show strong
completion message
- Skip for now: deferred connection (no nxCloudId), still show short URL
and update README
- No: full opt-out, set neverConnectToCloud: true in nx.json, no URL, no
README update, no cloud messaging

**CLI args:** `--nxCloud=skip`, `--nxCloud=never` (new),
`--nxCloud=yes`. Non-interactive defaults to skip.

Closes CLOUD-4242

(cherry picked from commit f7e46e33e9)
2026-02-26 16:35:12 -05:00
Jason Jean cf0d17405c chore(core): add tests for large directory file watching (#34601)
## Current Behavior

PR #34523 fixed the macOS file watcher issue (#34522) but did not
include comprehensive test coverage.

## Expected Behavior

Tests should verify that the fix works correctly and catch any future
regressions.

## Related Issue(s)

Adds test coverage for #34523 and #34522

---

## Changes

**TypeScript integration test**
(`packages/nx/src/native/tests/watcher.spec.ts`):

Added **"should detect file changes in large directory structures"** - a
comprehensive integration test that:
1. Creates 10,000+ directories simulating a monorepo-scale workspace
2. Starts a real `Watcher` instance
3. Creates and modifies files deep in the directory tree
4. Verifies that file change events are actually delivered

This test validates the actual behavior users care about - that file
watching works reliably in large repos - rather than testing
implementation details. It would catch any regression where events fail
to be delivered at scale.

## Testing

TypeScript integration test validates the actual bug fix - that file
events are delivered reliably in large directory structures with 10,000+
directories.

(cherry picked from commit 5d64f726d6)
2026-02-26 16:35:12 -05:00
Nikola Kalinov 2b72aa1fde fix(vite): isPreview=true for Vite Preview server (#34597)
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
Given the following Vite config:
```ts
import { defineConfig } from 'vite';

export default defineConfig((config) => {
  console.log(config);
  return {};
});
```

`npx nx preview` logs:
```ts
{
  mode: 'development',
  command: 'build',
  isSsrBuild: false,
  isPreview: false
}
```

## Expected Behavior
`npx nx preview` should log:
```ts
{
  mode: 'development',
  command: 'build',
  isSsrBuild: false,
  isPreview: true
}
```

## Related Issue(s)
https://github.com/vitejs/vite/issues/15694

Fixes #

(cherry picked from commit 1e1a8a7a40)
2026-02-26 16:35:12 -05:00
Leosvel Pérez Espinosa 00cb8d8a79 fix(core): remove unused getTerminalOutput from BatchProcess (#34604)
## Current Behavior

`BatchProcess` accumulates all stdout/stderr output in
`terminalOutputChunks` and exposes it via `getTerminalOutput()`, but
nothing ever calls `getTerminalOutput()`. The accumulated strings are
unique allocations (created via `chunk.toString()`), not shared with the
output callbacks or `process.stdout.write`.

For verbose batched tasks (e.g., Maven/Gradle with hundreds of tasks),
this can hold tens to hundreds of MB for the entire batch duration.

## Expected Behavior

Remove the dead accumulation code. stdout/stderr chunks are still
forwarded to `process.stdout`/`process.stderr` and output callbacks as
before — only the unused storage is removed.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
(cherry picked from commit 872b9c9045)
2026-02-26 16:35:12 -05:00
Jack Hsu ea2c77217d fix(js): remove redundant vite.config.ts generation for vitest projects (#34603)
## Current Behavior

When generating a library with vitest as the test runner and a non-vite
bundler (e.g. `tsc`), the js library generator creates two config files:
- `vitest.config.mts` (from the vitest `configurationGenerator`) with
`root: __dirname`
- `vite.config.ts` (from a second `createOrEditViteConfig` call) with
`root: import.meta.dirname`

The redundant `vite.config.ts` uses ESM-only `import.meta.dirname`
syntax, which causes TS1470 when the project targets CommonJS output:

```
vite.config.ts:5:9 - error TS1470: The 'import.meta' meta-property is not allowed in files which will build into CommonJS output.

5   root: import.meta.dirname,
          ~~~~~~~~~~~
```

## Expected Behavior

Only `vitest.config.mts` should be generated. The vitest
`configurationGenerator` already handles creating the correct config
file with `root: __dirname`. The second `createOrEditViteConfig` call
from `@nx/vite` was redundant and produced the conflicting file.

## Related Issue(s)

Fixes #34399

(cherry picked from commit 1e3f8e00f7)
2026-02-26 16:35:12 -05:00
Philip Fulcher 63d665298e docs(nx-dev): add foundations article (#34599)
(cherry picked from commit 919907cf0f)
2026-02-26 16:35:12 -05:00
Charlie Croom 54f43ff1fe fix(core): use recursive FSEvents on macOS instead of non-recursive kqueue (#34523)
## Current Behavior

Since Nx 22.5.0, the daemon's native file watcher silently drops all
file change events on macOS in large monorepos (~5,250+ watched
directories). `nx watch`, `nx serve`, and any daemon-dependent file
watching is broken.

The root cause is that #34329 switched all watched paths to
`WatchedPath::non_recursive()`. On macOS, the `notify` crate uses
**kqueue** for non-recursive watches instead of **FSEvents**. kqueue
silently fails at scale due to vnode table pressure (`kern.num_vnodes ==
kern.maxvnodes`), causing the daemon to never detect file changes.

This is a **scale-dependent** bug: it works fine in small workspaces
(~30 directories) but breaks silently in large ones.

| | **Nx 22.4.5** | **Nx 22.5.0+** |
|---|---|---|
| **Small repo (~30 dirs)** | Works (FSEvents) | Works (~30 kqueue
watches) |
| **Large repo (~5,250+ dirs)** | Works (FSEvents) | **Broken** (kqueue
silently drops all events) |

## Expected Behavior

The macOS file watcher should detect file creates, modifications, and
deletions at any scale, matching the behavior of Nx 22.4.x.

## Fix

Use platform-conditional watch modes:
- **macOS:** Single recursive watch on the workspace root (uses FSEvents
natively)
- **Linux/Windows:** Non-recursive per-directory watches (preserves the
#33781 inotify fix)

On macOS, FSEvents handles recursive watching from a single root path,
so directory enumeration and dynamic registration are skipped entirely.
This also improves daemon startup time on macOS from ~10 minutes to <1
second in a 354-project monorepo.

### What changed in `watcher.rs`

1. **Initial pathset:** On macOS, watch only the root directory
recursively via FSEvents instead of enumerating all directories for
non-recursive kqueue watches.
2. **Dynamic directory registration (`on_action`):** Wrapped in
`#[cfg(not(target_os = "macos"))]` since FSEvents already watches the
full tree.

Linux/Windows behavior is completely unchanged.

### Why the event filter is fine as-is

We verified that with recursive FSEvents watches, macOS emits specific
`FileEventKind` variants (`Create(File)`, `Modify(Data(Content))`,
`Remove(File)`, `Modify(Name(Any))`) that the current
`watch_filterer.rs` already handles correctly. Zero events were rejected
by the catch-all. The `Modify(Any)` / `Create(Any)` variants are kqueue
artifacts that are not needed with FSEvents.

### Why kqueue fails silently

Apple's [File System Events Programming
Guide](https://developer.apple.com/library/archive/documentation/Darwin/Conceptual/FSEvents_ProgGuide/KernelQueues/KernelQueues.html)
explicitly recommends FSEvents over kqueue for large hierarchies: *"If
you are monitoring a large hierarchy of content, you should use file
system events instead."* kqueue requires `open(path, O_EVTONLY)` per
watched directory. Under vnode table pressure, the kernel recycles
vnodes with kqueue watches attached without notifying the watcher. There
is no error, no partial delivery, and no diagnostic signal.

## Tested on

- macOS 26.3 (Tahoe), Apple Silicon (arm64), APFS
- 354-project pnpm monorepo (~19,865 non-ignored directories)
- Verified: file modifications, file creates, and file deletes all
detected
- Daemon init time: ~10 min (with enumeration) -> <1s (with root-only
FSEvents watch)

## Related Issue(s)

Fixes #34522

Co-authored-by: Amp <amp@ampcode.com>
(cherry picked from commit d5cd6a1a56)
2026-02-26 16:35:12 -05:00
Caleb Ukle 15a6856260 fix(nx-dev): correct interpolate sub command for cli reference (#34585)
also adding e2e for command hierarchy

<img width="823" height="362" alt="image"
src="https://github.com/user-attachments/assets/3db98945-4221-4bf3-8b92-9d5b25eb2444"
/>

<img width="778" height="349" alt="image"
src="https://github.com/user-attachments/assets/432ebd61-c34e-40f5-b95a-f8d73c682da4"
/>

![wm_2026-02-24T14-11-07@2x](https://github.com/user-attachments/assets/a3d635a3-b928-4ff2-a147-28f0873d26c2)

(cherry picked from commit 700c98fcaf)
2026-02-26 16:35:12 -05:00
Colum Ferry f01bb98ff8 fix(release): add null-safe fallback for version in createGitTagValues (#34598)
## Current Behavior

When nx release runs with docker-configured projects (either via
explicit config or
@nx/docker plugin inference), git tags are created with the literal
string {version}
instead of the actual version number (e.g., v{version} instead of
v1.0.6, or
  app-3@{version} instead of app-3@1.0.0).

  This happens because:

1. If ANY project in a release group has docker config,
preferDockerVersion is auto-set to
  true for the ENTIRE group
2. createGitTagValues() then blindly selects
projectVersionData.dockerVersion, which is
  null for non-docker projects (or projects with no changes)
3. The interpolate() function receives null for {version} and returns
the literal
  placeholder unchanged

Commit messages are unaffected because createCommitMessageValues() only
uses newVersion and
already guards against null. The changelog code (changelog.ts:1117-1121)
also already has
  the correct null-safe pattern.

 ## Expected Behavior

When preferDockerVersion is true but dockerVersion is null, git tags
should fall back to
using newVersion instead of producing literal {version} placeholders.
When both versions
  are null, no tag should be created.

For mixed release groups (some projects have docker config, some don't),
the auto-enable
logic should use 'both' mode instead of true, which already has proper
null-safe checks for
   each version type.

 ## Changes

- shared.ts: Added null-safe fallback (??) in createGitTagValues() for
both independent and
fixed group code paths, plus a guard to skip tag creation when both
versions are null
- config.ts: Refined auto-enable logic to check whether ALL or only SOME
projects have
  docker config — mixed groups now get 'both' mode instead of true
- shared.spec.ts: Added 5 test cases covering null version fallback
scenarios for fixed
groups, independent groups, both-null, reverse fallback, and mixed
groups

 ## Related Issue(s)

  Fixes #34382
  Fixes #33890
  Fixes #34391

(cherry picked from commit df9eb0bf10)
2026-02-26 16:35:11 -05:00
MaxKless a584ad8bd2 docs(misc): update nx download stats (#34596)
## Current Behavior
The "7. Thriving Community" section on
`nx.dev/docs/guides/adopting-nx/from-turborepo` displayed an outdated Nx
download statistic (~5 million downloads per week).

## Expected Behavior
The "7. Thriving Community" section on
`nx.dev/docs/guides/adopting-nx/from-turborepo` now reflects the latest
Nx download statistic (~9 million downloads per week).

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: MaxKless <MaxKless@users.noreply.github.com>
(cherry picked from commit 4e55f9aa32)
2026-02-26 16:35:11 -05:00
Jack Hsu 525969518b fix(bundling): fix regression on process.env usage for webpack (#34583)
When we optimized the `process.env` values to not embed the full object
unnecessarily, we also regressed in cases where users do use
`process.env` instead of `process.env["NX_PUBLIC_FOO"]`.

## Current behavior

Users cannot use `process.env` and must access each key individuall.
Although the serializing the full object can bloat bundle sizes, we also
don't want to break existing apps unnecessarily.

## Expected behavior

Existing apps should continue to work as usual.

## Related issues

Fixes #34279

(cherry picked from commit 127255aa96)
2026-02-26 16:35:11 -05:00
Kai Gritun aef9453375 fix(js): guard against undefined closest node in rehoistNodes (#34347)
## Current Behavior

When running `@nx/js:prune-lockfile` on a monorepo with transitive
dependencies that have multiple versions where neither version is
reachable from a direct dependency in package.json, the executor throws:

```
NX   An error occurred while creating pruned lockfile

Original error: Cannot read properties of undefined (reading 'name')

TypeError: Cannot read properties of undefined (reading 'name')
    at switchNodeToHoisted (node_modules/nx/src/plugins/js/lock-file/project-graph-pruning.js:165:31)
```

## Expected Behavior

The lockfile pruning should complete without crashing, even when some
transitive dependencies cannot be traced back to a direct dependency.

## Root Cause

In `rehoistNodes()`, when there are multiple nested nodes for a package,
the code finds the "closest" node by computing `pathLengthToIncoming()`
for each. However, when none of the nested nodes have a path to any
direct dependency in package.json, `pathLengthToIncoming()` returns
`undefined` for all of them. Since `undefined < Infinity` is `false` in
JavaScript, `closest` remains `undefined`, and then
`switchNodeToHoisted(undefined, ...)` crashes.

## Fix

Add a guard to only call `switchNodeToHoisted()` when a closest node was
actually found:

```typescript
if (closest) {
  switchNodeToHoisted(closest, builder, invBuilder);
}
```

This allows the pruning to continue - the nested nodes simply won't be
rehoisted if no closest node can be determined.

## Related Issue

Fixes #34322

## Test Added

Added a unit test that verifies `rehoistNodes()` doesn't crash when
nested nodes have no path to package.json dependencies.

(cherry picked from commit b46de60cd9)
2026-02-26 16:35:11 -05:00
Tomas Ptacek 1b1bcb7595 fix(angular-rspack): exclude .json files from JS/TS regex patterns (#34195)
## Current Behavior

When importing a `package.json` file in an Angular application built
with `@nx/angular-rspack`, the build fails with a Babel syntax error if
the `package.json` contains `@angular/*` dependencies:

```
SyntaxError: /path/to/package.json: Missing semicolon. (2:10)

  1 | {
> 2 |     "name": "@org/app",
    |           ^
  3 |     "version": "4.0.2",
  4 |     "dependencies": {
  5 |         "@angular/platform-browser": "20.3.7",
```

This happens because the `JS_ALL_EXT_REGEX` pattern
`/\.[cm]?(js)[^x]?\??/` incorrectly matches `.json` files. When the JSON
file content contains `@angular` strings, the
`angular-partial-transform-loader` attempts to process it through Babel,
which fails because JSON is not valid JavaScript.

**Root cause:** The regex `[^x]?` (optional character that is NOT 'x')
allows `.json` to match because 'o' is not 'x'.

## Expected Behavior
- `.json` files should NOT match `JS_ALL_EXT_REGEX` or
`TS_ALL_EXT_REGEX`
- Importing `package.json` in Angular applications should work correctly
- All existing matches for `.js`, `.jsx`, `.mjs`, `.cjs` (and TypeScript
equivalents) should continue to work

## Related Issue(s)
https://github.com/nrwl/nx/issues/32649
(cherry picked from commit 736551590a)
2026-02-26 16:35:11 -05:00
MaxKless 163f9dd25c chore(repo): update @nx/graph to 1.0.4 (#34558)
(cherry picked from commit e031d024ef)
2026-02-26 16:35:11 -05:00
Jason Jean 4d91125bf0 chore(gradle): clean up project.json configurations (#34587)
## Current Behavior

The Gradle projects have redundant and inconsistent project.json
configurations:
- `batch-runner` has its own project.json with duplicate targets
- `project-graph` has duplicate test/lint/format targets
- Implicit dependency syntax is inconsistent between projects
- e2e project has unnecessary implicitDependencies

## Expected Behavior

Cleaner, more maintainable project structure:
- Consolidated batch-runner configuration into parent project
- Removed duplicate targets from project-graph
- Consistent implicit dependency syntax using project name format
(`:project-name`)
- Streamlined e2e project configuration

## Related Issue(s)

N/A - Internal cleanup
Closes Q-173

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>
Co-authored-by: Louie Weng <56288712+lourw@users.noreply.github.com>
(cherry picked from commit d042483a3f)
2026-02-26 16:35:11 -05:00
Berend de Boer f7aad9cf4b docs(misc): add link to new nx-knip plugin (#34011)
This allows you to run knip against your typescript and javascript
projects.

Co-authored-by: Jack Hsu <jack.hsu@gmail.com>
(cherry picked from commit 39f252df97)
2026-02-26 16:35:10 -05:00
Aude Planchamp 661029f6c2 docs(misc): incorrect tsconfig inheritance described in TypeScript project references documentation (#34124)
## Current Behavior

Documentation bugfix on

https://nx.dev/docs/concepts/typescript-project-linking#set-up-typescript-project-references

In the section about setting up TypeScript project references, the
documentation currently states:

"Each project's tsconfig.lib.json file extends the project's
tsconfig.json file and adds references to the tsconfig.lib.json files of
project dependencies."

## Expected Behavior

In a standard Nx workspace configuration, tsconfig.lib.json extends the
workspace-level tsconfig.base.json, not the project-level tsconfig.json
(and the example provided just after is correct).

Suggested correction:

"Each project's tsconfig.lib.json file extends the workspace
tsconfig.base.json file and adds references to the tsconfig.lib.json
files of project dependencies."

## Related Issue(s)

Fixes  #34118

---------

Co-authored-by: Aude Planchamp <aude.planchamp@ekino.com>
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
Co-authored-by: Jack Hsu <jack.hsu@gmail.com>
(cherry picked from commit 3f70561586)
2026-02-26 16:35:10 -05:00
Miguel 0bbf0bfc59 fix(release): allow null values in schema of dockerVersion (#34171)
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

TS file documents `projectVersionData.dockerVersion` as having type
`string | undefined`. However, code behaves differently. For instance,
[here](https://github.com/nrwl/nx/blob/e57848cea748b85f17e5fc704b901975a8424c4d/packages/nx/src/command-line/release/version/release-group-processor.ts#L128)
and
[here](https://github.com/nrwl/nx/blob/e57848cea748b85f17e5fc704b901975a8424c4d/packages/nx/src/command-line/release/utils/shared.ts#L294)
it is setting as and comparing against `null`.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

Schema has value that code sets (`null`)

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes https://github.com/nrwl/nx/issues/34172

(cherry picked from commit b72a203ed7)
2026-02-26 16:35:10 -05:00
Craigory Coppola dab79e58d0 fix(core): reject pending promises directly when plugin worker exits unexpectedly (#34588)
When a plugin worker process exits unexpectedly, the exit handler
previously sent synthetic `loadResult` messages to all pending response
handlers. If any handler was waiting for a different result type (e.g.
`createNodesResult`), the type validation would reject with a confusing
"Expected createNodesResult, got loadResult" error instead of surfacing
the actual cause.

Split response handlers into `onMessage` / `onError` callbacks so the
exit handler can reject each pending promise directly with a clear
"Plugin worker exited unexpectedly" error.

Also use unique transaction IDs for `load` messages (via `generateTxId`)
to avoid potential handler overwrites during worker restarts.

Fixes #34564

(cherry picked from commit 1ecf0fb6a7)
2026-02-26 16:35:10 -05:00
Jason Jean 372d1d3e52 chore(repo): update nx to 22.6.0-beta.3 (#34579)
Updating Nx from 22.6.0-beta.2 to 22.6.0-beta.3

(cherry picked from commit c743313078)
2026-02-26 16:35:10 -05:00
Jason Jean dd77797fd3 chore(repo): disable CI continuous assignment (#34578)
## Summary

Testing CI behavior with continuous assignment disabled and cache bust
set to 4.

This is part of investigating flakiness potentially related to
continuous assignment in CI.

## Test plan

- Monitor CI execution behavior
- Compare with other test branches (bust=2, bust=3)

(cherry picked from commit 1bbe936513)
2026-02-26 16:35:10 -05:00
Jack Hsu cd6f7bbb0a docs(misc): dedupe and clean up getting started pages (#34521)
## Current Behavior

Documentation pages across Getting Started, How Nx Works, and Platform
Features sections contain:

1. Duplicated content — mental-model.mdoc has a ~70-line caching section
and a ~20-line DTE section that are near-verbatim
copies of how-caching-works.mdoc and distribute-task-execution.mdoc
respectively. remote-cache.mdoc re-explains local caching
 in its intro instead of linking to the canonical page.
2. Missing cross-reference links — Key concepts like "affected command",
"remote cache", "project graph", and "task pipeline
configuration" are mentioned without linking to their dedicated pages.
3. Style guide violations — Trust-undermining words ("simply", "just",
"straightforward"), anti-AI phrases ("Let's take",
"Whether you're..."), product possessives ("Nx's"), customer perspective
issues ("allows you to"), and em dashes appear
across Getting Started and How Nx Works pages.

## Expected Behavior

1. Content consolidation — mental-model.mdoc is trimmed by ~85 lines,
keeping the concept + images and linking to dedicated
pages for details. remote-cache.mdoc intro references the canonical
caching page. publish-conformance-rules-to-nx-cloud.mdoc
deduplicates its intro. maintain-typescript-monorepos.mdoc shortens its
inferred tasks re-explanation.
2. Cross-reference links added — First-mention links for affected,
remote cache, computation caching, task pipeline
configuration (in mental-model) and project graph (in self-healing-ci).
3. Style guide compliance — 18 fixes across 10 Getting Started and How
Nx Works pages, removing banned phrases and aligning
with the new STYLE_GUIDE.md.
4. Sidebar improvements — Cache Task Results added after Run Tasks in
Platform Features; Maintain TypeScript Monorepos moved
to first in KB > TypeScript.

## Pages changed
```
┌─────────────────┬─────────────────────────────────────────────────────────────────────────────────────────────────┐
│     Section     │                                              Pages                                              │
├─────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Getting Started │ intro, index, nx-cloud, ai-setup, start-with-existing-project                                   │
├─────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────┤
│ How Nx Works    │ mental-model, how-caching-works, task-pipeline-configuration, nx-plugins, nx-daemon             │
├─────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Features        │ remote-cache, self-healing-ci, maintain-typescript-monorepos, cache-task-results (sidebar only) │
├─────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Enterprise      │ publish-conformance-rules-to-nx-cloud                                                           │
└─────────────────┴─────────────────────────────────────────────────────────────────────────────────────────────────┘
```

(cherry picked from commit c966e20746)
2026-02-26 16:35:10 -05:00
Miroslav Jonaš 99b9b11c37 fix(repo): remove chalk from e2e tests (#34570)
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

(cherry picked from commit f42976f852)
2026-02-26 16:35:09 -05:00
Rares Matei c6ef8977bc chore(repo): enable signal file writing (#34572)
Add NX_CLOUD_IO_TRACING_DIRECTORY environment variable.

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes Q-245

(cherry picked from commit f84ec34cbd)
2026-02-26 16:35:09 -05:00
Juri 93bd3b5d15 docs(core): move synthetic monorepos back to "How Nx Works" sidebar section
(cherry picked from commit 566a370375)
2026-02-26 16:35:09 -05:00
Juri Strumpflohner 2bd0c34c1d docs(core): add synthetic monorepos page (#34565)
## Current Behavior

No documentation exists explaining the concept of synthetic monorepos —
how they bridge polyrepo and monorepo setups by connecting separate
repositories into a unified dependency graph.

https://deploy-preview-34565--nx-docs.netlify.app/docs/concepts/synthetic-monorepos

## Expected Behavior

New concept page under "How Nx Works" that explains:
- What synthetic monorepos are (unified graph across separate repos
without moving code)
- Why they matter for humans (visibility, cross-repo coordination) and
AI agents (seeing beyond repo boundaries)
- What they provide (cross-repo graph, actionable tooling, AI agent
enablement)
- How they serve as a gradual entry point toward deeper monorepo
adoption

## Related Issue(s)

N/A — new documentation page based on existing content from webinars and
internal knowledge.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: juristr <juristr@users.noreply.github.com>
(cherry picked from commit 4c1dd1e5ed)
2026-02-26 16:35:09 -05:00
Jack Hsu e653a0f371 fix(bundling): add docs link to generatePackageJson error message (#34562)
## Current Behavior

When users hit the `generatePackageJson: true` error with TS Solution
Setup, the error tells them to "unset the option" but gives no guidance
on the replacement workflow.

## Expected Behavior

The error message now includes a link to the pruning guide at
https://nx.dev/docs/technologies/node/guides/deploying-node-projects so
users can immediately find the migration steps.

## Related Issue(s)

Related #30146

(cherry picked from commit 7f7bba633d)
2026-02-26 16:35:09 -05:00
Colum Ferry 79e53cf3ce fix(js): use per-invocation cache in TS plugin to fix NX_ISOLATE_PLUGINS=false (#34566)
When plugin isolation is off, concurrent createNodesV2 invocations share
the same module instance. The module-level mutable `cache` variable
caused
invocation A's `finally` block to null it out while invocation B was
still
reading from it, resulting in "Cannot read properties of null (reading
'configContexts')".

Replace the shared mutable `cache` with a Symbol-keyed Map so each
invocation gets its own isolated cache. The tsconfig disk cache is
shared
across invocations with an idempotent initialization guard.

CLOSES NXC-3971

(cherry picked from commit 1a15ea183a)
2026-02-26 16:35:09 -05:00
Juri Strumpflohner 7bcdae8293 docs(nx-dev): add 'A Monorepo Is NOT a Monolith' blog post (#34567)
## Summary
- Updated version of the classic "Misconceptions about Monorepos"
article
- New sections on AI compatibility, scaling strategies (affected,
caching, distribution, atomization), and `@nx/owners`
- Custom SVG diagrams for project graph illustrations (replacing old
Medium images)
- Authors: Victor Savkin, Juri Strumpflohner

## Test plan
- [ ] Verify blog post renders correctly on preview
- [ ] Check all images load (SVGs + avif)
- [ ] Verify internal doc links resolve
- [ ] Check TOC renders properly

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: juristr <juristr@users.noreply.github.com>
(cherry picked from commit 8c0600225a)
2026-02-26 16:35:09 -05:00
MaxKless 5e95290211 feat(core): add passthrough for nx-cloud apply-locally command (#34557)
## Current Behavior
folks had to type in `nx-cloud apply-locally`

## Expected Behavior
now `nx apply-locally` works

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
(cherry picked from commit 832355081b)
2026-02-26 16:35:09 -05:00
MaxKless 7f813755fa feat(core): add --json flag for better AX to nx list (#34551)
### Current Behavior

nx list <plugin> shows generator/executor names and descriptions in text
format only. It does not show where the plugin or its
generators/executors are located on disk, and there is no
machine-readable output option.

  ### Expected Behavior

- nx list --json outputs all local and installed plugins with their
paths and capability types
- nx list <plugin> --json outputs detailed structured JSON including
resolved paths to each generator/executor implementation and schema
  - nx list <plugin> (text mode) now also shows the plugin's root path

(cherry picked from commit 1081c320ab)
2026-02-26 16:35:09 -05:00
Samuel Briole fd140b4bf6 fix(bundling): skip unnecessary type-check in TS Solution Setup when skipTypeCheck is true (#34493)
## Current Behavior

In TS Solution Setup, the esbuild executor forces `runTypeCheck` even
when `skipTypeCheck: true` and `declaration: false`, due to the `||
options.isTsSolutionSetup` condition in `esbuild.impl.ts` (lines 139-140
and 195).

When `declaration: false`, this type check runs in `noEmit` mode with
`ignoreDiagnostics: true` — making it **completely pointless** (no
declarations emitted, no diagnostics reported). Its only observable
effect is writing a poisoned 19-byte tsbuildinfo file that causes race
conditions with `tsc --build`.

## Expected Behavior

When `skipTypeCheck: true` and `declaration: false`, the esbuild
executor should not run type checking at all. The `isTsSolutionSetup`
override should only force type checking when declarations actually need
to be generated.

## Fix

### Primary: Skip unnecessary type check (`esbuild.impl.ts`)

```diff
  // Non-watch mode (line 195)
- if (!options.skipTypeCheck || options.isTsSolutionSetup) {
+ if (!options.skipTypeCheck || (options.isTsSolutionSetup && options.declaration)) {

  // Watch mode (lines 139-140)
- options.isTsSolutionSetup
+ (options.isTsSolutionSetup && options.declaration)
```

Only force type checking in TS Solution Setup when declarations need to
be generated. This eliminates the pointless type check entirely.

### Defense-in-depth: Prevent tsbuildinfo in `noEmit` mode
(`run-type-check.ts`)

```diff
- : { noEmit: true };
+ : { noEmit: true, composite: false };
```

Setting `composite: false` alongside `noEmit: true` prevents TypeScript
from writing tsbuildinfo files, protecting against this class of bug
from any caller of `runTypeCheck`.

## Why This is Safe

| Scenario | Before | After |
|----------|--------|-------|
| `skipTypeCheck: false`, `declaration: false`, `isTsSolutionSetup:
true` | Runs type check (noEmit) | Still runs (`!false \|\| ...` = true)
|
| `skipTypeCheck: false`, `declaration: true`, `isTsSolutionSetup: true`
| Runs type check (emitDeclarationOnly) | Still runs |
| `skipTypeCheck: true`, `declaration: true`, `isTsSolutionSetup: true`
| normalize.ts overrides skipTypeCheck to false; runs type check | Still
runs (same normalization) |
| **`skipTypeCheck: true`, `declaration: false`, `isTsSolutionSetup:
true`** | **Runs pointless type check (noEmit + ignoreDiagnostics),
writes poisoned tsbuildinfo** | **Skipped entirely** |

The only behavior change is in the last row — the case where the type
check was doing nothing useful but causing harm.

## Related Issue(s)

Fixes #34492

---------

Co-authored-by: Jack Hsu <jack.hsu@gmail.com>
(cherry picked from commit bdeeb036fb)
2026-02-26 16:35:08 -05:00
Jack Hsu 72a4ba3fd8 docs(node): add pruning guide for Docker deployments (#34560)
## Current Behavior

Users migrating to Nx 20's TS Solution Setup lose `generatePackageJson`
support and have no documentation on the replacement prune workflow
(`prune-lockfile`, `copy-workspace-modules`). The error message tells
them to "unset the option" but doesn't explain what to do instead.

## Expected Behavior

A dedicated guide at
`/docs/technologies/node/guides/deploying-node-projects` covers the full
prune workflow: when to use pruning vs bundling, target configuration,
Dockerfile setup, and step-by-step migration from `generatePackageJson`.

Also updated the existing bundling guide to match the same structure
(intro table, cross-links, style guide compliance). The two articles are
sister guides covering the two ways to deploy Node.js apps: bundle
everything into a single file, or prune dependencies for a
`node_modules`-based install.

Cross-links added from the bundling guide and ci-deployment guide.

## Related Issue(s)

Closes #30146

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: jaysoo <jaysoo@users.noreply.github.com>
(cherry picked from commit 4b1bf5f7ba)
2026-02-26 16:35:08 -05:00
Jack Hsu ff6b658914 docs(release): document checkAllBranchesWhen type and behavior (#34515)
## Current Behavior
The `checkAllBranchesWhen` option is documented as type `string` with a
minimal description, which does not match the actual implementation.

## Expected Behavior
Document the correct type (`boolean | string[]`) and explain the default
branch resolution behavior, the three value modes (true, false,
string[]), and when this option is useful.

## Related Issue(s)
Closes DOC-414

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: jaysoo <jaysoo@users.noreply.github.com>
(cherry picked from commit f935d9a7bf)
2026-02-26 16:35:08 -05:00
Jason Jean 6a8b0ffcf6 fix(core): retry entire SQLite transaction on DatabaseBusy (#34533)
## Current Behavior

When multiple Nx processes (task hasher, daemon, workers) access the
SQLite database concurrently, the `NxDbConnection::transaction()` method
only retries the BEGIN step using the `retry_db_operation_when_busy!`
macro. Operations executed inside the transaction and the COMMIT are not
retried, so if the database is busy during those steps, the task crashes
with:

```
Error: DB transaction operation error: SqliteFailure(Error { code: DatabaseBusy, extended_code: 5 }, Some("database is locked"))
```

This is particularly common during parallel task hashing with continuous
tasks, where `TaskDetails.recordTaskDetails()` and `RunningTasksService`
compete for write access.

## Expected Behavior

The entire transaction (begin, execute, commit) is retried as a single
unit when any step encounters a `DatabaseBusy` error. If the database is
busy during the operation or commit, the transaction is automatically
rolled back (via drop) and retried with the same exponential backoff
used everywhere else.

## Related Issue(s)

<!-- No public issue linked -->

(cherry picked from commit dd325d790a)
2026-02-26 16:35:08 -05:00
Jason Jean d1be68ec65 chore(repo): upgrade fast-xml-parser to 5.3.7 to fix CVE-2026-25896 (#34555)
## Current Behavior

The NPM audit CI job is failing due to a critical XSS vulnerability
(CVE-2026-25896) in `fast-xml-parser` version 4.5.3.

## Expected Behavior

The NPM audit should pass with no critical vulnerabilities.

## Related Issue(s)

Fixes the failing NPM audit CI run:
https://github.com/nrwl/nx/actions/runs/22288455713

---

This PR upgrades `fast-xml-parser` from `^4.2.7` to `^5.3.7` to address
GHSA-m7jm-9gc2-mpf2, a critical XSS vulnerability that allows entity
encoding bypass via regex injection in DOCTYPE entity names.

The package is only used in
`scripts/documentation/internal-link-checker.ts` for parsing XML
sitemaps, so the risk of this upgrade is low.

(cherry picked from commit ed786fb12c)
2026-02-26 16:35:08 -05:00
Jason Jean f4db9f478a chore(repo): update nx to 22.6.0-beta.2 (#34556)
Updating Nx from 22.6.0-beta.1 to 22.6.0-beta.2

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
(cherry picked from commit cf53d15ae5)
2026-02-26 16:35:08 -05:00
Mathias Schopmans e45f3e15ac fix(webpack): ensure safe process.env fallback replacement (#34464)
PR #30826 introduced a fallback definition for `process.env`:

```ts
{ 'process.env': '{}' }
```

Since `DefinePlugin` performs raw textual replacement, this can generate
invalid JavaScript when user code accesses environment variables via dot
notation:

```ts
process.env.SOME_KEY
```

becomes:

```js
{}.SOME_KEY
```

`{}` is parsed as a block statement (not an object literal), resulting
in:

> Unexpected token: punc (.)

This PR updates the fallback to a parenthesized object literal:

```ts
{ 'process.env': '({})' }
```

which produces valid output:

```js
({}).SOME_KEY
```

This preserves the intended bundle-size optimization while ensuring
syntactically correct output for standard `process.env.X` access
patterns.

## Related Issue(s)
Refs #30826
Fixes #34460

//CC @Coly010 @coolassassin

(cherry picked from commit 7351e21150)
2026-02-26 16:35:08 -05:00
MaxKless 48f5f47044 fix(misc): update maven & gradle icons to java duke icon (#34508)
duke is an official and open-source icon so we'll use it
<img width="1601" height="644" alt="image"
src="https://github.com/user-attachments/assets/3e95d94e-76d6-482a-ac09-bbe17a9f076a"
/>
<img width="1191" height="516" alt="image"
src="https://github.com/user-attachments/assets/151982fa-b497-4569-bf17-26f0d064d414"
/>

---------

Co-authored-by: Jason Jean <jasonjean1993@gmail.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
(cherry picked from commit 1805301941)
2026-02-26 16:35:08 -05:00
MaxKless f94714f6e9 fix(core): preserve existing source properties in claude plugin config (#34499)
## Current Behavior

Running `configure-ai-agents` overwrites the entire `source` object in
`extraKnownMarketplaces['nx-claude-plugins']`, removing any user-added
properties like `ref`.

## Expected Behavior

User-added source properties (e.g. `ref`) are preserved, while `source`
and `repo` are always set to the correct values.

(cherry picked from commit e8633e0299)
2026-02-26 16:35:08 -05:00
Colum Ferry bca15a5355 fix(angular): use SASS indented syntax in nx-welcome component when style is sass (#34510)
The nx-welcome component inline styles were always using CSS/SCSS syntax
(with braces and semicolons) regardless of the selected style option.
When --style=sass is chosen, the component now correctly uses SASS
indented syntax (no braces or semicolons) matching the expected
behavior for the .sass file format.

Fixes #33489

(cherry picked from commit 6bcaa46864)
2026-02-26 16:35:08 -05:00
Leosvel Pérez Espinosa c2272e4505 cleanup(repo): avoid unnecessary project graph recomputations (#34423)
## Current Behavior

- Cypress `start-dev-server.ts` file creates a port lock file next to
the source code
- Native temp DB files created by tests are not properly ignored
- Astro config timestamp file is not ignored

These all trigger watch file change events, which cause the project
graph to be recomputed unnecessarily.

## Expected Behavior

Output files should not trigger watch file change events. The project
graph should not be recomputed unnecessarily.

(cherry picked from commit 025db33a75)
2026-02-25 22:20:06 -05:00
Leosvel Pérez Espinosa a72c78b113 fix(misc): bump minimatch to 10.2.1 to address CVE-2026-26996 (#34509)
## Current Behavior

Several Nx packages directly depend on a minimatch version with a
high-severity vulnerability
(https://github.com/advisories/GHSA-3ppc-4f35-3m26).

## Expected Behavior

Several Nx packages should depend directly on a minimatch version that
does not include the reported high-severity vulnerability.

Note: unsafe `minimatch` versions can still be pulled in transitively.
Upstream deps need to be updated, and then we need to update the Nx
packages to newer versions.

## Related Issue(s)

Fixes #34507

---------

Co-authored-by: Jason Jean <jasonjean1993@gmail.com>
(cherry picked from commit 731db47fd7)
2026-02-25 22:20:06 -05:00
Copilot 590bfb3106 docs(core): clarify trailing slash requirement for inputs directory paths (#33664)
## Current Behavior

Users specifying directory paths in `inputs` without a trailing slash or
glob pattern find that files are not matched. For example,
`{projectRoot}/src` does not match any files, while `outputs` allows
naked directory paths without issue.

## Expected Behavior

Documentation clearly explains that directory paths in `inputs` require
a trailing slash or glob pattern:

```jsonc
{
  "inputs": [
    "{projectRoot}/src/",       // ✓ Works (trailing slash)
    "{projectRoot}/src/**/*",   // ✓ Works (glob pattern)
    "{projectRoot}/src"         // ✗ Does NOT work
  ]
}
```

### Changes

- **Reference doc** (`reference/inputs.mdoc`): Added "Directory Paths"
section explaining the requirement with examples
- **Guide** (`configure-inputs.mdoc`): Added callout warning at top
alerting users to this behavior
- Both docs note the difference from `outputs`, which do support naked
directory paths

## Related Issue(s)

Fixes
https://linear.app/nxdev/issue/NXC-2102/clarify-trailing-slash-requirement-for-inputs-in-directory-paths

Co-authored-by: Steven Nance <steven@nrwl.io>
(cherry picked from commit 4b6aea9f5e)
2026-02-25 22:20:06 -05:00
Altan Stalker 806a7d7745 chore(repo): force nx-dev:prebuild-banner onto linux-extra-large (#34535)
Temp fix while scheduling is fixed for real

---------

Co-authored-by: FrozenPandaz <jasonjean1993@gmail.com>
(cherry picked from commit 0568059fb8)
2026-02-25 22:20:06 -05:00
Jack Hsu 23666229b0 fix(misc): prevent nxCloudId from being generated for new workspaces (#34532)
## Current Behavior

When creating a new workspace using `create-nx-workspace` with the
"custom" preset flow, an `nxCloudId` is generated and added to
`nx.json`. This happens even though the onboarding flow is supposed to
handle Cloud setup separately via a short URL.

## Expected Behavior

New workspaces created via `create-nx-workspace` should not have
`nxCloudId` set in `nx.json`. Instead, a short URL is provided for users
to finish Cloud onboarding on their own. The `nxCloud: 'skip'` option is
now passed for the custom flow to prevent the ID from being generated.

E2E tests are updated to verify that `nxCloudId` is undefined in the
generated `nx.json` across all workspace presets.

## Related Issue(s)

N/A - internal fix for workspace creation behavior.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
(cherry picked from commit 221ed882fa)
2026-02-20 15:03:01 -05:00
Craigory Coppola 744cb3a555 fix(core): commands shouldn't hang when passing --help (#34506)
## Current Behavior
`--help` on commands that hit yargs help are hanging

## Expected Behavior
It doesn't hang. This contains a quick fix in adding the process.exit
call, but also adds the unref needed to maintain previous working
behavior. We'll need to investigate long term if additional areas keep
commands alive, but adding this unref theoretically allows removing the
process.exit calls from `nx show`

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

---------

Co-authored-by: Jason Jean <jasonjean1993@gmail.com>
(cherry picked from commit df8a2c43f4)
2026-02-20 15:03:01 -05:00
Jason Jean 4bb6006ed2 chore(repo): re-enable e2e tests disabled by api-extractor issue (#34519)
## Current Behavior

14 e2e test suites were disabled (`xdescribe`) due to an ESM import
issue in `@microsoft/api-extractor@7.57.0` (see
https://github.com/qmhc/unplugin-dts/issues/461).

## Expected Behavior

With the upstream issue resolved, all 14 e2e test suites are re-enabled
(`describe`) and should pass normally.

## Related Issue(s)

Reverts #34516

(cherry picked from commit 391d23c65e)
2026-02-20 12:25:59 -05:00
Jason Jean 6d11e28cd3 chore(repo): update nx to 22.6.0-beta.1 (#34527)
Updating Nx from 22.5.0-beta.5 to 22.6.0-beta.1

(cherry picked from commit 092cea6073)
2026-02-20 12:25:59 -05:00
Jack Hsu 24ddad041b fix(nextjs): reset daemon client after project graph creation in withNx (#34518)
## Current Behavior

Running `nx test` for Next.js projects causes Jest to hang with:
```
Jest did not exit one second after the test run has completed.
```

This happens because `next/jest` loads `next.config.js`, which calls
`withNx` → `createProjectGraphAsync()`. The daemon client socket
connection is left open, keeping the Node.js event loop alive and
preventing Jest from exiting. Non-Next.js projects are unaffected since
they don't trigger this code path.

## Expected Behavior

Jest exits cleanly after tests complete for Next.js projects, without
needing `forceExit: true`.

## Fix

Pass `resetDaemonClient: true` to `createProjectGraphAsync()` in
`packages/next/plugins/with-nx.ts`. This tells the project graph
function to call `daemonClient.reset()` after fetching the graph, which
closes the socket and allows Jest to exit.

### Verification

| Scenario | Before | After |
|----------|--------|-------|
| `nx test next-app` | Hangs | Exits cleanly |
| `NX_DAEMON=false nx test next-app` | Exits cleanly | Exits cleanly |
| Direct `npx jest` | Exits cleanly | Exits cleanly |
| Non-Next.js `nx test react-lib` | Exits cleanly | Exits cleanly |

## Related Issue(s)

Fixes #32880

(cherry picked from commit de2dc7ca13)
2026-02-20 12:25:58 -05:00
Altan Stalker 3d90c94951 chore(core): enable nx cloud verbose logging (#34524)
## Current Behavior
Agents are silent and hard to diagnose

## Expected Behavior
Agents should print debug logs without making all of Nx print debug logs

(cherry picked from commit 8e1d873edc)
2026-02-20 12:23:23 -05:00
Jason Jean c4df82922a chore(repo): disable e2e tests broken by @microsoft/api-extractor@7.57.0 (#34516)
## Current Behavior

14 e2e tests are failing across master with "Failed to process project
graph" errors. The root cause is `@microsoft/api-extractor@7.57.0` which
has a broken ESM export (`ConsoleMessageId`). When `@nx/vite/plugin` or
`@nx/vitest` plugins load `vite.config.mts` files, they transitively
import api-extractor which crashes.

## Expected Behavior

Broken e2e tests are disabled via `xdescribe` so they no longer block
CI. Tests should be re-enabled once the upstream api-extractor ESM issue
is fixed.

## Disabled Tests

| Project | Test File |
|---------|-----------|
| e2e-vite | `vite.test.ts`, `vite-legacy.test.ts`,
`vite-ts-solution.test.ts` |
| e2e-vue | `vue.test.ts`, `vue-legacy.test.ts`,
`vue-ts-solution.test.ts` |
| e2e-js | `js-ts-solution.test.ts` |
| e2e-web | `web-vite.test.ts` |
| e2e-react | `react-vite.test.ts`, `react-ts-solution.test.ts` |
| e2e-next | `next-ts-solutions.test.ts` |
| e2e-release | `release-publishable-libraries.test.ts`,
`release-publishable-libraries-ts-solution.test.ts` |
| e2e-storybook | `storybook-nested.test.ts` |

## Related Issue(s)

Upstream: https://github.com/qmhc/unplugin-dts/issues/461
(cherry picked from commit 4ca3ee97c3)
2026-02-20 12:23:22 -05:00
Jason Jean 1f0dac4cb5 chore(maven): upgrade maven-shade-plugin to 3.6.0 (#34514)
## Current Behavior

The `maven-shade-plugin` at version 3.5.0 intermittently fails on CI
with:

```
Could not replace original artifact with shaded artifact!
```

This is a file-locking race condition where the plugin fails to
atomically replace the original JAR with the shaded JAR.

## Expected Behavior

Upgrading to 3.6.0 resolves the intermittent CI failures by using
improved file-handling logic with better retry behavior during the
artifact replacement step.

## Related Issue(s)

N/A - fixes intermittent CI flakiness in `maven-batch-runner` builds.

(cherry picked from commit e6ad74afed)
2026-02-20 12:23:22 -05:00
Ondrej Kelle d11f35ce44 feat(core): use static_vcruntime to avoid msvcrt dependency (#19781)
Closes #19779

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

## Current Behavior
When targeting Windows the resulting binary (nx.dll) dynamically links
against Microsoft Visual C++ runtime (msvcrt140.dll). This means nx
won't be able to run on Windows systems without this runtime installed.

## Expected Behavior
I'd like to avoid this dependency by linking the runtime statically into
the nx binary. (This is also how e.g. cargo.exe for Windows is built.)

## Related Issue(s)

Fixes #19779

---------

Co-authored-by: Craigory Coppola <craigorycoppola@gmail.com>
(cherry picked from commit 79f41e54af)
2026-02-20 12:23:21 -05:00
Leosvel Pérez Espinosa ff238feef0 fix(core): reduce terminal output duplication and allocations in task runner (#34427)
## Current Behavior

Terminal output in the task runner is accumulated via repeated string
concatenation (`terminalOutput += chunk`). Each `+=` on a growing string
causes V8 to allocate a new, larger string and copy the old contents,
resulting in O(n²) allocation behavior for tasks with large output.
Additionally, `PseudoTtyProcess.onExit` didn't pass `terminalOutput` to
its callbacks, forcing callers like `TaskOrchestrator` to duplicate
output accumulation logic with a separate `onOutput` listener.

## Expected Behavior

- Terminal output is collected in `string[]` arrays and joined once at
the end, reducing intermediate allocations from O(n²) to O(n)
- `PseudoTtyProcess.onExit` now passes `terminalOutput` as a second
argument, matching the signature of other `RunningTask` implementations
- `TaskOrchestrator` no longer needs a special code path for
`PseudoTtyProcess` — unified `onExit` handling for all task types
- `tui-summary-life-cycle` accumulates output in chunks during execution
and stores the finalized string on task completion, allowing chunk
arrays to be GC'd
- `SeriallyRunningTasks` and `RunningNodeProcess` similarly switched to
chunk-based accumulation
- `BatchProcess` and `NodeChildProcessWithNonDirectOutput` lazily join
and cache their terminal output

(cherry picked from commit 4f9be499b4)
2026-02-20 12:23:20 -05:00
Caleb Ukle fb41fd940d docs(nx-dev): tech intro page structure improvements (#34450)
Work on making a tech intro pages more consistent with each other and
focus on "answering the 80%" for the given technology.

Focusing on
- Angular
- Maven/Gradle
- react
- TS
- Vite
- Vitest/Jest

The changes are based around answering the following, where each
"category" of page might have a different set of depth for the answer.

1. Why do I want to use this plugin?
- Plugins are considered fully optional and are aimed at providing
better DX for a technology, such as inferred setup, generators,
migrations.
- some plugins (like TSC) might have special call outs in some of this,
but generally the same for all plugins.
2. How do I use this plugin in my workspace?
  - also pretty commonly the "same" for all plugins in terms of "setup"
- where they differ is mostly for frameworks, e.g. Angular, React.
You're looking at setting up a project to use these tools
- For Build/Test tools you're looking at adding to an existing project,
or converting from one to another.
- Build/Test tools are "means to an end", so should callout if the goal
is tool + framework in a "new" context point to the framework based
plugin page. Otherwise, show adding to an existing project like React
project.
3. What do I need to know about using this plugin?
- understanding finer details of a plugin options, e.g. buildable &
publishable
  - extra generators for the plugin. e.g. "convert-to-swc"
- generally I like the idea of having a "CI considerations" where we
talk about CI setups that can help, e.g. options or batch mode etc.

closes DOC-407

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: barbados-clemens <barbados-clemens@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
(cherry picked from commit 42b534366d)
2026-02-20 12:23:20 -05:00
Caleb Ukle ede36d4954 fix(nx-dev): update breadcrumb links to match sidebar (#34500)
navigation of the breadcrumbs could lead to confusing state since they
were based around the folder structure.

Breadcrumbs are now based around the sidebar structure so they match the
hierarchy of content.

Note: I left the existing index file based route pages in place in case
there are any links people have booked marked/linked to in other
locations. these will get cleaned up when we finally rewrite all the
URLs to their new content locations

(cherry picked from commit 7528cc51fa)
2026-02-20 12:22:41 -05:00
Caleb Ukle 85085dd223 fix(nx-dev): widen search dialog (#34504)
(cherry picked from commit bbb1baa631)
2026-02-20 12:22:40 -05:00
Leosvel Pérez Espinosa a731e551f5 fix(core): skip stale recomputations and prevent lost file changes in daemon (#34424)
## Current Behavior

When file changes arrive rapidly, the daemon triggers multiple
concurrent project graph recomputations that all run to completion —
wasting CPU/memory on redundant work and returning stale results.

Additionally, after processing file changes, the daemon clears all
tracked files indiscriminately. Files that changed mid-recomputation are
silently lost and never reflected in the project graph until another
unrelated file change arrives.

## Expected Behavior

Stale recomputations detect when a newer one has started and exit early,
chaining to the newer promise so callers always get the freshest result.

File change tracking now uses versioned maps. Each batch of file watcher
events gets a unique version, and only files matching the snapshotted
version are cleared after processing. Files that changed
mid-recomputation are preserved and picked up by the next cycle.

(cherry picked from commit 91b350efa8)
2026-02-20 12:22:40 -05:00
Jason Jean 570d03e626 fix(repo): fix e2e CI failures from Node 22.12 incompatibility (#34501)
## Current Behavior

Two categories of e2e CI failures were observed in run
https://github.com/nrwl/nx/actions/runs/22127884259:

1. **`e2e-nx-init` and `e2e-js` fail on Node 22.12.0** with:
   ```
error eslint-visitor-keys@5.0.0: The engine "node" is incompatible with
this module.
   Expected version "^20.19.0 || ^22.13.0 || >=24". Got "22.12.0"
   ```
Node 22.12.0 is one minor version short of the `^22.13.0` range required
by `eslint-visitor-keys@5.0.0`.

2. **`e2e-nx` tests fail because `[isolated-plugin]` / `[plugin-worker]`
verbose messages leak into captured stdout**, causing:
- `JSON.parse(runCLI('show project --json'))` to throw `SyntaxError:
Unexpected token 'i', "[isolated-p"...`
- `expect(runCLI('show projects')).toEqual('')` to fail with worker
spawn noise
- The `@nx/workspace:infer-targets` test to unexpectedly find
`@nx/remix` in output (from a worker spawn message)

Root cause: in `isolated-plugin.ts`, the plugin worker's stdout was
piped directly to `process.stdout`, so `[plugin-worker]` verbose
messages written by the worker ended up in the stdout captured by
`runCLI` in e2e tests.

## Expected Behavior

1. The CI matrix uses a Node 22.x version that satisfies `^22.13.0`.

2. Plugin worker verbose/diagnostic messages go to `process.stderr` (not
`process.stdout`), so they don't contaminate output captured by `runCLI`
in e2e tests. Both worker stdout and stderr now pipe to
`process.stderr`, and the max listener bump is consolidated to `+2` on
stderr.

## Related Issue(s)

N/A — identified from CI run
https://github.com/nrwl/nx/actions/runs/22127884259

(cherry picked from commit 50ca951540)
2026-02-20 12:22:39 -05:00
MaxKless b8dbbdcb9c fix(maven): write output after each task in batch mode to ensure correct files are cached (#34400)
## Current Behavior
When running in maven 4 batch mode, the build state is recorded only
after the full batch is done.
This means that nx caching records the state of a task before build
state is recorded to disk.
When running another maven task that depends on this partially recorded
cache, the build state file is missing and we get errors.

## Expected Behavior
build state should be recorded after every task is done and before nx
caching can kick in. This way we can ensure that nx cache is correct.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
(cherry picked from commit 18bfb0bc4a)
2026-02-20 12:22:39 -05:00
Simon Heather 16669f89fb docs(core): add cacheKeyPrefix option to s3 remote cache options (#34157)
This pull request updates the documentation for the S3 cache plugin to
add the missing `cacheKeyPrefix` setting.

Text taken from https://github.com/nrwl/nx/pull/31395

Fixes #34147

---------

Co-authored-by: Caleb Ukle <caleb@nrwl.io>
Co-authored-by: Caleb Ukle <caleb.ukle+github@pm.me>
Co-authored-by: Simon Heather <simon.heather@yulife.com>
(cherry picked from commit bdf6d257b7)
2026-02-20 12:22:24 -05:00
Leosvel Pérez Espinosa ff9b6c3a8c fix(core): replace buggy ignore-files trie with correct path-component gitignore matching (#34447)
## Current Behavior

The `nx watch` file watcher uses the `ignore-files` and
`watchexec-filterer-ignore` crates to handle `.gitignore` matching.
These crates use a trie-based approach that has a bug with
path-component matching — certain gitignore patterns (e.g., prefix
patterns) don't match correctly, causing files that should be ignored to
trigger unnecessary watch events.

## Expected Behavior

Gitignore patterns are matched correctly using per-directory `Gitignore`
instances from the `ignore` crate — the same crate already used by the
file walker. Each `.gitignore` file is scoped to its directory, and
matching is done deepest-first so that nested gitignores take priority —
matching standard git behavior.

### What changed

- Replaced `ignore-files` + `watchexec-filterer-ignore` with direct use
of `ignore::gitignore::{Gitignore, GitignoreBuilder}`, aligning the
watcher with the approach already used by the file walker
- Each `.gitignore` is now compiled as a standalone instance tied to its
parent directory
- Gitignore evaluation walks deepest-first; first match wins
- `.nxignore` matching now uses `matched_path_or_any_parents` for
correct ancestor checking
- `create_filter` is now synchronous (no longer `async`) since the new
approach doesn't need async I/O
- Removed 2 crate dependencies (`ignore-files`,
`watchexec-filterer-ignore`)

(cherry picked from commit 678cd321f5)
2026-02-20 12:22:24 -05:00
Jay Bell e1b7b7383e fix(core): use workspace root for path resolution when baseUrl is not set (#34453)
## Current Behavior

When a project-level `tsconfig.json` (e.g., `apps/aurora/tsconfig.json`)
inherits `paths` via `extends` from `tsconfig.base.json` at the
workspace root and no explicit `baseUrl` is set, Nx incorrectly resolves
`./`-prefixed path mappings relative to the project tsconfig directory
instead of the workspace root where the paths were defined.
This causes errors when loading TypeScript config files (e.g.,
`rspack.config.ts`) that import workspace libraries using path aliases:
  NX   Cannot find module './libs/plugins/rspack/src'

`@swc-node/register`'s `readDefaultTsConfig` auto-sets `baseUrl` to
`dirname(tsConfigPath)` (the project directory) when not explicitly
configured, causing SWC to rewrite imports to incorrect relative paths
during transpilation.

  ## Expected Behavior

Path aliases defined in `tsconfig.base.json` (e.g.,
`"@trellis/plugins/rspack": ["./libs/plugins/rspack/src/index.ts"]`)
should resolve relative to the workspace root when no `baseUrl` is
configured.

This is needed so that when using `tsgo` and needing to prefix all paths
with `./` (no more `baseUrl` allowed) the paths are still resolved from
the right spot.

I tested this fix against our codebase on the branch I was trying to
switch to tsgo on and it seemed to work.

  ## Related Issue(s)

Fixes
https://discord.com/channels/1143497901675401286/1471627045694865581

(cherry picked from commit a0e34557f9)
2026-02-20 12:22:16 -05:00
Altan Stalker 5e4bbf92fd chore(core): enable continuous assignment (#34471)
## Current Behavior
Continuous assignment is not enabled

## Expected Behavior
Continuous assignment is enabled

(cherry picked from commit 5c7c9dd5fa)
2026-02-20 12:22:16 -05:00
Juri Strumpflohner 8efaf179ab docs(repo): update CONTRIBUTING.md with Discord link (#34461)
## Current Behavior

CONTRIBUTING.md contains an outdated "How to Get Started Video" section
and references Stack Overflow for general questions.

## Expected Behavior

Remove outdated video section and point users to the Discord community
instead of Stack Overflow for general questions.

## Related Issue(s)

N/A

(cherry picked from commit 4f31277f4f)
2026-02-20 12:22:15 -05:00
Colum Ferry 68cc3b06fd feat(misc): use caret range for swc dependencies in pnpm catalog (#34487)
Use a range for the swc dependencies

Fixes #34472

(cherry picked from commit c16377af25)
2026-02-20 12:22:15 -05:00
Craigory Coppola 865a99e1c7 fix(core): avoid blocking event loop during TUI PTY resize (#34385)
When switching from inline mode to full-screen TUI (or during window
resize), the PTY resize operation reparsed ALL raw terminal output
through a new vt100 parser synchronously on the event loop. For tasks
with large output, this caused a noticeable hang.

Add `resize_async()` which moves the expensive reparse to a background
thread using a snapshot-and-replay pattern:
1. Quick snapshot of raw output (brief read lock)
2. Expensive reparse on background thread (no locks held)
3. Quick swap with replay of any new output (brief write lock)

A generation counter prevents stale resizes from overwriting newer ones.

Also combine two separate O(n) scrollback processing calls in inline
mode into a single pass.

(cherry picked from commit 130cec466f)
2026-02-20 12:21:58 -05:00
Copilot a0ae06aeb2 chore(repo): update copyright year to 2026 and refresh README description (#34437)
## Current Behavior

Copyright year shows 2017-2025 and README uses older tagline.

## Expected Behavior

Copyright reflects current year 2026 and README uses updated repository
description.

## Changes

- **LICENSE**: Updated copyright year from `2017-2025` to `2017-2026`
- **README.md**: Replaced heading and description
- New heading: "The Monorepo Platform that amplifies both developers and
AI agents. Nx optimizes your builds, scales your CI, and fixes failed
PRs automatically. Ship in half the time."
  - Removed redundant description line below heading

<!-- START COPILOT ORIGINAL PROMPT -->

<details>

<summary>Original prompt</summary>

> ## Update License and README
>
> Please make the following changes:
>
> 1. **Update LICENSE file**: Change the copyright year from `2017-2025`
to `2017-2026`
>    - File: `LICENSE`
> - Line 3: Update `Copyright (c) 2017-2025 Narwhal Technologies Inc.`
to `Copyright (c) 2017-2026 Narwhal Technologies Inc.`
>
> 2. **Update README.md description**: Replace the current description
with the repository's official description
>    - File: `README.md`
> - Line 22: Change the heading from `# Smart Monorepos · Fast Builds`
to `# The Monorepo Platform that amplifies both developers and AI
agents. Nx optimizes your builds, scales your CI, and fixes failed PRs
automatically. Ship in half the time.`
> - Line 24: Remove the current description line: `Get to green PRs in
half the time. Nx optimizes your builds, scales your CI, and fixes
failed PRs. Built for developers and AI agents.`
>
> The new README should have the repository description as the main
heading, followed immediately by the "Create a new Nx workspace with"
section.

</details>

<!-- START COPILOT CODING AGENT SUFFIX -->

*This pull request was created from Copilot chat.*
>

<!-- START COPILOT CODING AGENT TIPS -->
---

💬 We'd love your input! Share your thoughts on Copilot coding agent in
our [2 minute survey](https://gh.io/copilot-coding-agent-survey).

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: FrozenPandaz <8104246+FrozenPandaz@users.noreply.github.com>
Co-authored-by: Jason Jean <jasonjean1993@gmail.com>
(cherry picked from commit 65b94a1293)
2026-02-20 12:21:57 -05:00
Leosvel Pérez Espinosa c2c8b99616 fix(core): gate tui-logger init behind NX_TUI env var (#34426)
## Current Behavior

`tui_logger::init_logger()` and `TuiTracingSubscriberLayer` are
initialized unconditionally in `initialize_logger()`. This spawns a
background thread, causing unnecessary allocation churn and increased
processing.

## Expected Behavior

`tui_logger` is only initialized when `NX_TUI=true`, avoiding the
background thread and allocation overhead for all non-TUI contexts.

(cherry picked from commit 896a3f31ad)
2026-02-20 12:21:57 -05:00
Caleb Ukle b1e325560c chore(nx-dev): condense redirect rules (#34452)
## Current Behavior

We have ~1,657 redirect rules across `redirect-rules.js` and
`redirect-rules-docs-to-astro.js`, getting close to Netlify's limit and
we need room for more as the Astro migration continues.

## Expected Behavior

Reduced to **1,139 rules** (~31% reduction) by:

- Resolving duplicate/conflicting source paths across sections
- Flattening multi-hop redirect chains to point directly to final
destinations
- Consolidating groups of individual rules into wildcard patterns
(tutorials, CLI, helm, concepts, recipes, etc.)
- Removing old 2022-era sections (`schemaUrls`, `overviewUrls`,
`packagesIndexes`, `packagesDocuments`) whose destinations chain 3-5
hops deep and are long superseded by newer redirects
- made sure old links in nx code base still have redirects (will update
in future PR)

Build, tests, and internal link check all pass with no issues.

## Related Issue(s)

Fixes DOC-403

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: barbados-clemens <barbados-clemens@users.noreply.github.com>
(cherry picked from commit ea81b52442)
2026-02-20 12:21:56 -05:00
Caleb Ukle e6c8c1200a fix(nx-dev): use shared preview url for netlify deploy (#34467)
nextjs and astro should route to same preview deployments now

![wm_2026-02-16T19-40-04](https://github.com/user-attachments/assets/593c011a-ff78-4412-9bf0-ad186157f5d4)

(cherry picked from commit edc9cc5af8)
2026-02-20 12:21:56 -05:00
MaxKless fb9098f400 fix(core): only pull configure-ai-agents from latest if local version is not latest (#34484)
## Current Behavior
we pull from latest all the time even if the current version is already
latest

## Expected Behavior
we can skip this extra work sometimes

(cherry picked from commit ee22084d1a)
2026-02-20 12:21:47 -05:00
Jack Hsu 13c3a7633f fix(misc): rewrite Framer URLs to nx.dev in HTML responses (#34445)
## Current Behavior

Pages proxied from Framer contain canonical URLs pointing to the Framer
domain (`ready-knowledge-238309.framer.app`), causing duplicate indexing
issues in search engines.

## Expected Behavior

Canonical URLs and other references in Framer-proxied pages now point to
`nx.dev`, ensuring proper SEO indexing.

### Implementation

Consolidated all Framer logic into a single Netlify edge function
(`rewrite-framer-urls.ts`) that:

1. Checks if the request path matches a Framer-proxied path (using
`FRAMER_REWRITES` env var)
2. Fetches directly from Framer (using `FRAMER_URL` env var)
3. Rewrites all Framer URLs to `nx.dev` in the HTML response (handles
`<link rel="canonical">`, `og:url`, etc.)
4. For non-Framer paths, passes through to Next.js

The edge function uses the `accept: ['text/html']` config to only run on
HTML requests, matching the pattern from `track-page-requests.ts` in
astro-docs.

The Next.js middleware has been removed since all Framer routing is now
handled by the edge function.

### Environment Variables

The edge function expects these env vars in Netlify (already added
previously):
- `NEXT_PUBLIC_FRAMER_URL`: e.g.,
`https://ready-knowledge-238309.framer.app`
- `NEXT_PUBLIC_FRAMER_REWRITES`: comma-separated list of paths, e.g.,
`/pricing,/enterprise`

## Demo

1. Go to https://deploy-preview-34445--nx-dev.netlify.app/
2. View source and look for canonical
3. See it is nx.dev not framer domain

<img width="1347" height="161" alt="image"
src="https://github.com/user-attachments/assets/d4a515da-e39f-41cb-a7b4-668fe0bedbbd"
/>

## Related Issue(s)

Closes CLOUD-4148

(cherry picked from commit ca2fc0fa85)
2026-02-20 12:21:46 -05:00
Steven Nance 3705d1d7e3 fix(release): remove unnecessary number from release return type (#34481)
## Current Behavior

The `release` function returned by `createAPI` has a return type of
`Promise<NxReleaseVersionResult | number>`. The `| number` union member
is inaccurate since the function always returns
`NxReleaseVersionResult`, which can mislead consumers of the
programmatic API.

## Expected Behavior

The return type is narrowed to `Promise<NxReleaseVersionResult>`,
accurately reflecting what the function actually returns and giving API
consumers correct type information.

Co-authored-by: Andreas Hörnicke <andreas.hoernicke@contentful.com>
(cherry picked from commit 0c14bcbe55)
2026-02-20 12:21:46 -05:00
MaxKless d674bc8a61 docs(misc): update nx-mcp reference and tweak ai docs for skills (#34468)
we changed the default options of the nx mcp so we need to update docs
to reflect it

(cherry picked from commit 08d899a2d2)
2026-02-20 12:21:45 -05:00
MaxKless 5665a871b5 docs(nx-dev): add MCP to skills blog post (#34428)
Blog post draft about the evolution from MCP tools to agent skills.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: MaxKless <MaxKless@users.noreply.github.com>
Co-authored-by: Juri Strumpflohner <juri.strumpflohner@gmail.com>
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
(cherry picked from commit 0d4160e968)
2026-02-20 12:21:44 -05:00
Leosvel Pérez Espinosa b96f7bbe19 fix(core): prevent staggered and duplicate lines in dynamic output (#34462)
## Current Behavior

- In some `nx run-many` executions, terminal output can appear staggered
or visually misaligned instead of updating cleanly in place.
- For `run-many` cases that end up running a single task (especially
when TUI is not active), the spinner/status line can be rendered twice.

## Expected Behavior

- Dynamic terminal output updates should remain stable and aligned, with
clean in-place refreshes.
- Single-task `run-many` should display a single spinner/status line
with no duplicate rendering.

(cherry picked from commit 59b12edcb6)
2026-02-20 12:21:37 -05:00
Juri 9128fcb66f fix(core): handle Ctrl+C gracefully in configure-ai-agents
Add uncaughtException handler for ERR_USE_AFTER_CLOSE to prevent
ugly stack trace when pressing Ctrl+C during enquirer prompts
(Node 24 stricter readline behavior). Matches existing pattern
used in nx init and create-nx-workspace.

(cherry picked from commit dd3b79ebf4)
2026-02-20 12:21:36 -05:00
Jason Jean 24948ec290 fix(repo): revert sudo for global npm install in publish workflow (#34451)
## Current Behavior

The publish workflow uses `sudo npm install -g npm@11.5.2` which was
added in #34409. This causes issues with OIDC token permissions in the
release pipeline since `sudo` runs as a different user context.

## Expected Behavior

The publish workflow should use `npm install -g npm@11.5.2` without
`sudo`, matching the standard approach used elsewhere and avoiding
permission context issues during release.

## Related Issue(s)

Reverts #34409
2026-02-13 15:54:46 -05:00
Jack Hsu 58a7c5ad14 docs(misc): minor fixes for docs (#34449)
1. Consistent punctuation on intro page (periods at end of bullet
points).
2. Adjust AI detection for edge function.
2026-02-13 15:54:45 -05:00
Jason Jean 699e8d06c1 fix(repo): replace addnab/docker-run-action with direct docker run (#34448)
## Current Behavior

The publish workflow uses `addnab/docker-run-action@v3` which is based
on `docker:20.10` (Docker API 1.41). GitHub's `ubuntu-24.04` runners now
ship Docker Engine 28.x which requires minimum API version 1.44, causing
all 4 Linux Docker builds to fail:

```
docker: Error response from daemon: client version 1.41 is too old. Minimum supported API version is 1.44, please upgrade your client to a newer version.
```

Failed run: https://github.com/nrwl/nx/actions/runs/21961139962

## Expected Behavior

Linux Docker builds (x86_64-gnu, x86_64-musl, aarch64-gnu, aarch64-musl)
complete successfully using the host's modern Docker CLI.

https://github.com/nrwl/nx/actions/runs/21996143819

## Related Issue(s)

The `addnab/docker-run-action` repo is abandoned (last release March
2021, last commit May 2021) with open issues about this exact problem.

(cherry picked from commit c5e1bedca2)
2026-02-13 13:03:47 -05:00
Jack Hsu 7be8cb20ab docs(misc): improve AX for getting started pages (#34410)
## Current Behavior

Getting started pages had overlapping content and unclear focus:
- `installation.mdoc` mentioned CNW and tutorials (belongs elsewhere)
- `start-new-project.mdoc` had manual setup option (belongs on
add-to-existing)
- `start-with-existing-project.mdoc` duplicated CI examples, editor
buttons, Nx Cloud walkthrough
- `intro.mdoc` mixed messaging - some "challenges" were polyrepo
problems

## Expected Behavior

Each page is now focused with no duplication:

### intro.mdoc
- Clear problem/solution structure following Turborepo's approach
- Problem: concise (builds get slow as codebase scales)
- Solution: caching, task orchestration, affected commands
- **Removed**: Polyrepo problems from challenge list (code sharing, lost
context)
- **Removed**: Lengthy deepdive callouts
- Net reduction: 67 deletions, 14 insertions

### installation.mdoc
- Global install (npm/brew/choco/apt) + verification step
- Local install (`nx init`) for existing repos
- Update instructions
- **Removed**: CNW mention, tutorials section, "More Documentation"

### start-new-project.mdoc
- Option 1: Create locally with templates (`create-nx-workspace`)
- Option 2: Create via Nx Cloud (browser-based)
- **Removed**: Manual setup option (that's for existing projects)
- Updated terminology: "presets" → "templates"

### start-with-existing-project.mdoc
- Focused: `nx init` → run tasks → see caching → explore graph
- Links to other pages instead of duplicating content
- **Removed**: CI config examples, Nx Cloud walkthrough, editor buttons

### editor-setup.mdoc
- Added problem hook explaining why editor integration matters
- Clarified Neovim is community-maintained

### ai-setup.mdoc
- Added problem hook about AI hallucination without workspace context
- Explained MCP acronym (Model Context Protocol)
- Clarified "Ralph Wiggum loop" terminology

### sidebar.mts
- Reordered to match natural flow: Installation → Start New/Add Existing
→ Editor/AI

## Related Issue(s)

Closes DOC-405

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: jaysoo <jaysoo@users.noreply.github.com>
(cherry picked from commit c0540c8846)
2026-02-13 12:34:39 -05:00
Craigory Coppola cbc9c4d371 fix(core): remove shellapi from winapi featureset to minimize AV false positives (#34208)
## Current Behavior
There's a chance that windows can falsely flag our native binaries as a
threat. We do not use the shellapi feature from winapi.

## Expected Behavior
We hope that removing this API doesn't break things, and the threat
messaging goes away

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #https://github.com/nrwl/nx/issues/34186

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
(cherry picked from commit ece9b5bf4a)
2026-02-13 12:34:38 -05:00
Craigory Coppola e6aa96d535 chore(repo): improve copy-built-package script (#34432)
Makes copy-built-package script a bit more ergonomic and discoverable.
Adds some interactive UI for picking package / repo if they are not
specified.

(cherry picked from commit 51420790c3)
2026-02-13 12:34:38 -05:00
Craigory Coppola da7b1e03a4 fix(core): hitting [1] or [2] should remove pinned panes if they match the current task (#34433)
## Current Behavior

Pressing `[1]` or `[2]` on a task that's already pinned to that slot
**focuses** the pane instead of unpinning it. This means there's no way
to unpin a single pane via keyboard — you can only nuke everything with
`[0]`.

This regression was introduced in #34175, which fixed a real problem:
pressing Enter on an already-pinned task would unpin it, leaving focus
on an invisible pane (a ghost pane — you're staring at nothing but the
TUI thinks you're looking at output). The fix was to make the "already
pinned to this pane" branch focus instead of unpin. The problem is that
`[1]`, `[2]`, and Enter all flowed through the same function
(`assign_current_task_to_pane`), so changing behavior for Enter changed
it for everyone. One lock got swapped out, and every door started
behaving the same way.

## Expected Behavior

`[1]` and `[2]` are **toggles**: press once to pin, press again to
unpin. Enter is a **display** action: show me this task's output and put
my cursor there — if it's already visible somewhere, just take me to it.

After this change:

- **`[1]` / `[2]`** on an already-pinned task → unpins it (pane
disappears, layout adjusts, focus returns to task list if no panes
remain)
- **Enter** on an already-pinned task → focuses whichever pane it's in
(even if it's in pane 2 and you'd normally expect pane 1)
- **Init** (startup restore of pinned tasks) → pure assignment, no
toggling, no focusing

## Approach

The old code had one function trying to serve three masters. Rather than
adding a flag parameter (`should_toggle: bool`) — which would just be a
boolean that lies about its intentions at every call site — the function
was split along the actual semantic boundaries:

| Function | Used by | "Already pinned here" behavior |
|---|---|---|
| `toggle_current_task_in_pane` | `[1]` / `[2]` keys | **Unpin** (toggle
off) |
| `assign_current_task_to_pane` | `init()` | No-op (task is where it
should be) |
| `display_and_focus_current_task_in_terminal_pane` | Enter key |
**Focus** the existing pane |

The shared logic — exiting spacebar mode, moving a task between panes,
fresh-pinning — lives in two small helpers (`exit_spacebar_and_pin`,
`move_or_pin_selection`) that both `toggle` and `assign` delegate to.
The only code that differs is the "what do we do when it's already
here?" branch, which is exactly the part that *should* differ.

**Why not keep one function with a mode parameter?** Because the three
behaviors aren't variations of the same action — they're genuinely
different user intents. A toggle is "I changed my mind." A focus is
"Take me there." An assignment is "Put this here." Encoding that as an
enum parameter just moves the branching somewhere less obvious and makes
the call sites harder to read. The function names now document the
intent at the point of use, and there's no shared state to accidentally
couple.

**Why does Enter check all panes, not just pane 0?** Because if you
pinned a task to pane 2 via `[2]` and then press Enter on it, the least
surprising thing is to jump to where it already lives — not to silently
duplicate it into pane 1 or ignore you. The task is already on screen;
Enter means "show me."

## Related Issue(s)

Fixes the regression introduced by #34175.

(cherry picked from commit c407de6e2b)
2026-02-13 12:34:37 -05:00
Jack Hsu 3c5965fa7d feat(misc): lock in CNW variant 2 with deferred connection (#34416)
## Current Behavior

CNW (Create Nx Workspace) has A/B testing logic that randomly selects
between variants 0, 1, and 2 for the Nx Cloud connection flow. Each
variant shows different prompts and banners.

## Expected Behavior

Lock in variant 2 as the permanent behavior:
- **No cloud prompt** - users are not asked about Nx Cloud during
workspace creation
- **Deferred connection** - no `nxCloudId` is written to `nx.json` (uses
`skipCloudConnect: true`)
- **Variant 2 banner** - shows "Enable remote caching and automatic
fixes when CI fails" with a link to complete setup later

### Changes
- Simplified `ab-testing.ts` - removed caching, random selection;
`getFlowVariant()` always returns `'2'`
- `shouldShowCloudPrompt()` always returns `false`
- `determineNxCloudV2()` returns `'github'` with `skipCloudConnect:
true` for deferred connection
- Removed variant 1 banner logic from `messages.ts`
- Updated tests to reflect the locked-in behavior

## Demo

https://www.loom.com/share/7f688eed6052428cbe91dd9db837cbbd

## Related Issue(s)

Closes CLOUD-4255

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
(cherry picked from commit 950265fc8c)
2026-02-13 12:34:37 -05:00
Benjamin Cabanes 9438bbf38a docs(nx-dev): replace global ID with deterministic target ID for HBST (#34431)
Simplified form targeting by replacing the global `reactHubspotForm` ID
with a deterministic `targetId` that incorporates portal, form, and
calendly IDs. This improves scalability and avoids potential ID
collisions.

(cherry picked from commit 28fea0db0c)
2026-02-13 12:34:36 -05:00
Benjamin Cabanes 4127de2378 docs(nx-dev): add back inline script (#34429)
(cherry picked from commit b5c3663126)
2026-02-13 12:34:35 -05:00
MaxKless 9f68bae9fc fix(maven): correctly map between maven locators and nx project names (#34366)
(cherry picked from commit a757f40d83)
2026-02-13 12:34:35 -05:00
Jack Hsu 5587eab6a5 chore(misc): add banner content monitor workflow (#34417)
## Current Behavior

When banner content changes in Framer, the nx-docs and nx-dev sites need
to be manually redeployed to pick up the new content.

## Expected Behavior

A scheduled workflow monitors the banner URL every 15 minutes and
automatically triggers Netlify production deploys when content changes.

## How it works

1. Fetches `BANNER_URL` content (from repository variable)
2. Computes SHA256 hash
3. Compares to cached hash from previous run
4. If different → triggers both Netlify deploys, updates cache
5. If unchanged → no-op

## Required Setup

1. **Repository variable** (`Settings → Secrets and variables → Actions
→ Variables`):
   - `BANNER_URL` = Framer banner API URL

2. **Repository secret** (`Settings → Secrets and variables → Actions →
Secrets`):
   - `NETLIFY_AUTH_TOKEN` = Netlify personal access token

## Related Issue(s)

Fixes DOC-405

(cherry picked from commit 7a4e052533)
2026-02-13 12:34:34 -05:00
Juri 3f18d78edd docs(nx-dev): add Nx AI agent skills blog post
(cherry picked from commit 9a57042cbe)
2026-02-13 12:34:34 -05:00
Steven Nance 501fd5780e feat(core): add negation pattern support for plugin include/exclude (#34160)
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
Negation patterns are ignored in plugin configuration for the `include`
and `exclude` properties.

## Expected Behavior

- Negation patterns should work in the same way that they do for other
`include`/`exclude` configurations

**Example: Excluding all e2e projects except one**

```jsonc
// nx.json
{
  "plugins": [
    {
      "plugin": "@nx/jest/plugin",
      "exclude": ["**/*-e2e/**/*", "!**/toolkit-workspace-e2e/**/*"],
    },
  ],
}
```

This will exclude all e2e projects except `toolkit-workspace-e2e`.

**Example: Including packages except legacy ones**

```jsonc
// nx.json
{
  "plugins": [
    {
      "plugin": "@nx/vite/plugin",
      "include": ["packages/**/*", "!packages/legacy/**/*"],
    },
  ],
}
```

**How negation patterns work:**

- Patterns are processed in order from first to last
- A pattern starting with `!` removes files from the match set
- A pattern without `!` adds files to the match set
- The last matching pattern determines if a file is included
- If the first pattern is a negation, all files are matched initially

---------

Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
(cherry picked from commit 754b01a066)
2026-02-13 12:34:33 -05:00
Colum Ferry cf11551811 feat(misc): update PLUGIN.md files to help agents verification (#34379)
## Current Behavior
There is currently no plugin.md file for Gradle.
Other plugin.md files can be improved

## Expected Behavior
Add plugin.md file for Gradle to aid with verification with Agents.
Add plugin.md file for Vite for workspaces that have not migrated to
@nx/vitest.

## Related Issue(s)

CLOSES NXC-3843

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: Coly010 <Coly010@users.noreply.github.com>
(cherry picked from commit 5a1735b041)
2026-02-13 12:34:32 -05:00
Josh VanAllen ff1b8d83b5 feat(testing): add cacheDir option to playwright executor (#34413)
## Current Behavior

The Playwright executor does not support configuring a custom cache
directory for Playwright's internal cache (browser binaries, etc.).
Users who need to control where Playwright stores its cache, for example
in CI environments with specific disk constraints like not being able to
DTE tasks or shared caching setups, have no way to set this through the
executor configuration.

## Expected Behavior

A new `cacheDir` option is available on the Playwright executor. When
provided, it sets the `PWTEST_CACHE_DIR` environment variable on the
forked Playwright process, allowing users to control where Playwright
stores its internal cache.
  ```json
  {
    "targets": {
      "e2e": {
        "executor": "@nx/playwright:playwright",
        "options": {
          "cacheDir": "/tmp/playwright-cache"
        }
      }
    }
  }
  ```

## Related Issue(s)

Replaces #34397

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
(cherry picked from commit a0ff232ad7)
2026-02-13 12:34:32 -05:00
Jack Hsu a62dadcbb4 docs(misc): clarify security email usage in SECURITY.md (#34411)
## Current Behavior

The SECURITY.md file does not clarify what types of reports should be
sent to the security email, leading to reports about outdated
dependencies and vulnerability scanner output.

## Expected Behavior

The file now clarifies that the security email is for demonstrable,
verified vulnerabilities in the Nx codebase itself, not for:
- Outdated dependency reports
- Dependencies with CVEs that don't directly affect Nx
- General vulnerability scanner output

## Related Issue(s)

Fixes NXC-3898

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
(cherry picked from commit 17f2f1bdc6)
2026-02-13 12:34:21 -05:00
Jason Jean 0d99f7d1c0 fix(repo): use sudo for global npm install in publish workflow (#34409)
## Current Behavior

The `npm install -g npm@11.5.2` step in the publish workflow fails with
`EACCES: permission denied, mkdir '/usr/local/share/man/man5'` on newer
GitHub Actions runner images.

## Expected Behavior

The global npm install step completes successfully regardless of runner
image permissions on `/usr/local/share/man/`.

## Related Issue(s)

This is a known issue with GitHub Actions runners:
https://github.com/actions/runner-images/issues/9644

(cherry picked from commit e48f2f3a8c)
2026-02-13 12:34:21 -05:00
Colum Ferry 13acb88990 feat(core): extract sandbox detection into reusable utility (#34408)
Add isSandbox() utility that checks for sandbox environment variables
(SANDBOX_RUNTIME, GEMINI_SANDBOX, CODEX_SANDBOX, CURSOR_SANDBOX) and
use it to disable the daemon and plugin isolation in sandbox
environments.

(cherry picked from commit 7785eae516)
2026-02-13 12:34:20 -05:00
Miroslav Jonaš a2636a283d fix(nx-dev): clarify project linking for workspaces (#34405)
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: meeroslav <meeroslav@users.noreply.github.com>
(cherry picked from commit 28c5d95964)
2026-02-13 12:34:20 -05:00
Caleb Ukle 9f3293a3a5 fix(nx-dev): add missing nx-cloud intro in sidebar (#34403)
(cherry picked from commit 0e53c3f3d5)
2026-02-13 12:34:19 -05:00
Colum Ferry d3bed1b2f6 feat(core): handle agentic sandboxing (#34402)
## Current Behavior
Running ai agents in sandbox mode causes issues with Nx's daemon and
plugin isolation

## Expected Behavior
Running ai agents in sandbox mode should work

## Related Issue(s)

CLOSES NXA-828

(cherry picked from commit 6bf8c4693f)
2026-02-13 12:34:18 -05:00
Philip Fulcher 8bc5188a1f docs(nx-dev): add broadcom success story (#34393)
(cherry picked from commit 8e3cff657b)
2026-02-13 12:34:18 -05:00
Colum Ferry 5e65513d5c feat(core): add nxVersion to meta in shortUrl for cnw (#34401)
## Current Behavior
We do not include NxVersion when creating short urls.

## Expected Behavior
Include NxVersion when creating short urls.

## Related Issue(s)

CLOSES NXC-3879

(cherry picked from commit 15d508e814)
2026-02-13 12:34:17 -05:00
Craigory Coppola 1b1c702d76 fix(core): handle dangling symlinks during cache restore (#34396)
When cache outputs include both glob patterns and directory patterns
containing symlinks, the cache restore fails with EEXIST (os error 17).
This happens because `fs_extra::remove_items` silently skips dangling
symlinks (since `is_dir()`/`is_file()` follow links and return false),
leaving stale symlinks that cause `symlink()` to fail.

The fix makes symlink creation idempotent by checking for and removing
any existing symlink at the destination before creating a new one, using
`symlink_metadata()` which correctly detects dangling symlinks.

Fixes #34013

(cherry picked from commit 6570674abf)
2026-02-13 12:34:17 -05:00
Jason Jean 893404aea8 fix(maven): use module-level variable for cache transfer between createNodes and createDependencies (#34386)
## Current Behavior

The Maven plugin's `createNodes` and `createDependencies` functions both
independently compute a hash of all pom.xml directories, then use that
hash to look up cached Maven analysis data from disk. When Maven
projects have `<includes>` or `<excludes>` in their plugin config, the
hash can differ between the two calls, causing `createDependencies` to
fail to find the data that `createNodes` stored.

## Expected Behavior

`createDependencies` reliably receives the Maven analysis data from
`createNodes` regardless of hash differences, by reading it from a
module-level variable instead of re-hashing and looking it up from disk.

This matches the pattern already used by the Gradle plugin
(`getCurrentGradleReport`).

## Related Issue(s)

(cherry picked from commit 2d71d9ac65)
2026-02-13 12:34:16 -05:00
Leosvel Pérez Espinosa 42920fc8b8 fix(core): make runtime cache key deterministic (#34390)
## Current Behavior

Runtime cache keys could be nondeterministic because the order of
environment variables varied, leading to inconsistent cache hits across
runs.

## Expected Behavior

Runtime cache keys are deterministic regardless of the insertion order
of env variables, improving cache stability.

(cherry picked from commit f43d2028ff)
2026-02-13 12:34:16 -05:00
Leosvel Pérez Espinosa 7c80accd05 fix(core): avoid dropping unrelated continuous deps in makeAcyclic (#34389)
## Current Behavior

Cycles in the task graph could remove unrelated `continuousDependencies`
when the cycle exists only in `dependencies`, leading to missing
continuous task edges.

## Expected Behavior

Cycle removal only removes the specific cyclic edge from the list where
it appears, preserving unrelated continuous dependencies.

(cherry picked from commit 6c9f0cb46d)
2026-02-13 12:34:15 -05:00
Caleb Ukle c3a9980ed5 fix(nx-dev): improve plugin registry visibility (#34395)
- **fix(nx-dev): make sure "plugin registry" shows up in search**
- search ranking will be re-evaled after we work through more content
updates
<img width="768" height="1406" alt="image"
src="https://github.com/user-attachments/assets/e7ca2aff-7daf-417b-ad96-ba6722480432"
/>

- **docs(nx-dev): add plugin registry to footer**
<img width="1076" height="405" alt="image"
src="https://github.com/user-attachments/assets/4c93c5ec-1f64-4cd6-8f88-9347d5009ac9"
/>

(cherry picked from commit bd13929de8)
2026-02-13 12:34:14 -05:00
Brett Burley 7d5655d4d6 fix(core): clean up stale socket files before listening (#34236)
## Current Behavior

When running Nx tasks in CI environments (e.g., Buildkite) where the
host's /tmp is mounted to containers, intermittent EADDRINUSE errors
occur in PseudoIPCServer.init(). This happens because:

1. PseudoIPCServer doesn't clean up its Unix socket file before calling
listen()
2. ForkedProcessTaskRunner.createPseudoTerminal() instantiates
PseudoTerminal directly instead of using the createPseudoTerminal()
helper, bypassing shutdown callback registration

When a new container starts with the same PID as a previous run (PID
recycling), it generates the same socket path and hits EADDRINUSE
because the stale socket file still exists.

## Expected Behavior

No EADDRINUSE errors should occur. The PseudoIPCServer should
defensively remove any stale socket file before attempting to listen,
similar to how the daemon server handles this.

## Related Issue(s)

Fixes #34233

(cherry picked from commit f5a7ea1606)
2026-02-13 12:34:14 -05:00
Benjamin Cabanes 95fceaeaa1 docs(nx-dev): remove Cookiebot & GA integration, migrate all events to GTM (#34384)
Streamlined analytics tracking by removing Cookiebot and direct GA
(gtag.js) integrations. Consolidated event logging through GTM's
dataLayer for consistency and maintenance simplicity.

(cherry picked from commit 9c42292ed8)
2026-02-13 12:34:13 -05:00
Altan Stalker f5fc93eff9 chore(core): enable cloud experimental polling (#34394)
Updated CI behavior

(cherry picked from commit ec0f51ed75)
2026-02-13 12:34:13 -05:00
Leosvel Pérez Espinosa 00eb405d69 fix(core): use a consistent batch id between scheduler and task runner (#34392)
## Current Behavior

Batch IDs are generated in two places: the task scheduler uses an
incremental counter (`executorName N`) while the forked process task
runner generates its own using the process PID (`executorName-pid`).
This means the batch ID registered in metrics doesn't match the one used
everywhere else.

## Expected Behavior

Batch IDs are only created by the task scheduler. The forked process
task runner uses the scheduler-assigned ID to ensure consistency across
the system.

(cherry picked from commit 5ae53ecae8)
2026-02-13 12:34:12 -05:00
MaxKless 3badb93f5c fix(core): make sure that mcp args aren't overridden when running configure-ai-agents (#34381)
## Current Behavior
right now if users modify their mcp params like `--minimal`, we will
override them on `configure-ai-agents`

## Expected Behavior
We want to bring users up to latest without overriding their valid
configurations

(cherry picked from commit 5066511576)
2026-02-13 12:34:11 -05:00
Benjamin Staneck 7d5b8592df feat(core): update formatting of agent rules documentation (#33356)
(cherry picked from commit 0b6961b0d7)
2026-02-13 12:34:10 -05:00
437 changed files with 16728 additions and 7940 deletions
+92
View File
@@ -0,0 +1,92 @@
name: Banner Content Monitor
on:
schedule:
- cron: '*/15 * * * *'
workflow_dispatch: # Allow manual trigger
permissions: {}
env:
BANNER_URL: ${{ vars.BANNER_URL }}
jobs:
check-and-deploy:
if: ${{ github.repository_owner == 'nrwl' }}
runs-on: ubuntu-latest
steps:
- name: Fetch banner content and compute hash
id: banner
run: |
if [ -z "$BANNER_URL" ]; then
echo "BANNER_URL is not set"
exit 1
fi
# Fetch content and compute hash
CONTENT_HASH=$(curl -sf "$BANNER_URL" | sha256sum | cut -d' ' -f1)
if [ -z "$CONTENT_HASH" ]; then
echo "Failed to fetch banner content"
exit 1
fi
echo "current_hash=$CONTENT_HASH" >> $GITHUB_OUTPUT
echo "Current banner hash: $CONTENT_HASH"
- name: Restore cached hash
id: cache
uses: actions/cache/restore@v4
with:
path: .banner-hash
key: banner-content-hash-
restore-keys: |
banner-content-hash-
- name: Compare hashes
id: compare
run: |
CURRENT_HASH="${{ steps.banner.outputs.current_hash }}"
if [ -f .banner-hash ]; then
CACHED_HASH=$(cat .banner-hash)
echo "Cached hash: $CACHED_HASH"
else
CACHED_HASH=""
echo "No cached hash found"
fi
if [ "$CURRENT_HASH" != "$CACHED_HASH" ]; then
echo "changed=true" >> $GITHUB_OUTPUT
echo "Banner content has changed!"
else
echo "changed=false" >> $GITHUB_OUTPUT
echo "Banner content unchanged"
fi
- name: Trigger Netlify deploys
if: steps.compare.outputs.changed == 'true'
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
run: |
npm install -g netlify-cli
echo "Triggering nx-docs deploy..."
netlify deploy --trigger --prod -s nx-docs
echo "Triggering nx-dev deploy..."
netlify deploy --trigger --prod -s nx-dev
echo "Both deploys triggered successfully"
- name: Save new hash to cache
if: steps.compare.outputs.changed == 'true'
run: |
echo "${{ steps.banner.outputs.current_hash }}" > .banner-hash
- name: Update cache
if: steps.compare.outputs.changed == 'true'
uses: actions/cache/save@v4
with:
path: .banner-hash
key: banner-content-hash-${{ github.run_id }}
+5 -2
View File
@@ -30,6 +30,9 @@ jobs:
NX_ALLOW_NON_CACHEABLE_DTE: 'true'
NX_CLOUD_USE_NEW_TASK_APIS: 'true'
NX_CLOUD_USE_NEW_STREAM_OUTPUT: 'true'
NX_CLOUD_EXPERIMENTAL_POLLING: 'true'
NX_CLOUD_CONTINUOUS_ASSIGNMENT: 'false'
NX_CLOUD_VERBOSE_LOGGING: 'true'
steps:
- name: Checkout
@@ -75,7 +78,7 @@ jobs:
pnpm playwright install --with-deps
- name: Nx Report
run:
run:
pnpm nx report
- name: Run Checks/Lint/Test/Build
@@ -94,7 +97,7 @@ jobs:
pnpm nx run-many -t check-imports check-lock-files check-codeowners --parallel=1 --no-dte &
pids+=($!)
pnpm nx affected --targets=lint,test,test-kt,build,e2e,e2e-ci,format-native,lint-native &
pnpm nx affected --targets=lint,test,build,e2e,e2e-ci,format-native,lint-native,gradle:build-ci &
pids+=($!)
for pid in "${pids[@]}"; do
+1 -1
View File
@@ -75,7 +75,7 @@ const matrixData: MatrixData = {
os_name: 'Linux',
os_timeout: 60,
package_managers: ['npm', 'pnpm', 'yarn'],
node_versions: ['20.19.0', '22.12.0', '24.0.0'],
node_versions: ['20.19.0', '22.13.0', '24.0.0'],
excluded: ['e2e-detox', 'e2e-react-native', 'e2e-expo']
},
// Docker is not supported on ARM-based macOS runners (no nested virtualization)
+17 -5
View File
@@ -354,12 +354,24 @@ jobs:
architecture: x86
- name: Build in docker
uses: addnab/docker-run-action@4f65fabd2431ebc8d299f8e5a018d79a769ae185 # v3
if: ${{ matrix.settings.docker }}
with:
image: ${{ matrix.settings.docker }}
options: --user 0:0 -v ${{ github.workspace }}/.cargo-cache/git/db:/usr/local/cargo/git/db -v ${{ github.workspace }}/.cargo/registry/cache:/usr/local/cargo/registry/cache -v ${{ github.workspace }}/.cargo/registry/index:/usr/local/cargo/registry/index -v ${{ github.workspace }}:/build -w /build
run: ${{ matrix.settings.build }}
shell: bash
env:
BUILD_SCRIPT: ${{ matrix.settings.build }}
run: |
SCRIPT_FILE=$(mktemp)
echo "$BUILD_SCRIPT" > "$SCRIPT_FILE"
docker run --rm \
--user 0:0 \
-e PNPM_VERSION \
-v ${{ github.workspace }}/.cargo-cache/git/db:/usr/local/cargo/git/db \
-v ${{ github.workspace }}/.cargo/registry/cache:/usr/local/cargo/registry/cache \
-v ${{ github.workspace }}/.cargo/registry/index:/usr/local/cargo/registry/index \
-v ${{ github.workspace }}:/build \
-v "$SCRIPT_FILE:/build-script.sh" \
-w /build \
${{ matrix.settings.docker }} \
bash /build-script.sh
- name: Build
run: ${{ matrix.settings.build }}
+2 -2
View File
@@ -29,7 +29,7 @@ jest.debug.config.js
# Banner JSON files are generated during static builds
/nx-dev/nx-dev/lib/banner.json
/astro-docs/src/content/banner.json
**/tests/temp-db
**/tests/temp-db*
# Issues scraper creates these files, stored by github's cache
/scripts/issues-scraper/cached
@@ -71,7 +71,7 @@ dependency-reduced-pom.xml
*.wasm
/wasi-sdk*
vite.config.*.timestamp*
*.config.timestamp*
storybook-static
+1
View File
@@ -8,6 +8,7 @@ common-env-vars: &common-env-vars
# These are need for build and link validation for next.js and astro apps
NEXT_PUBLIC_ASTRO_URL: 'https://master--nx-docs.netlify.app'
NX_DEV_URL: 'https://canary.nx.dev'
NX_CLOUD_IO_TRACING_DIRECTORY: '~/io-tracing'
common-init-steps: &common-init-steps
- name: Checkout
+15
View File
@@ -7,6 +7,12 @@ distribute-on:
assignment-rules:
- projects:
- e2e-gradle
targets:
- e2e-ci**
run-on:
- agent: linux-extra-large
parallelism: 1
- projects:
- e2e-next
- e2e-plugin
targets:
@@ -94,6 +100,15 @@ assignment-rules:
- agent: linux-extra-large
parallelism: 6
# TODO(altan): remove when scheduling issue resolved
- projects:
- nx-dev
targets:
- prebuild-banner
run-on:
- agent: linux-extra-large
parallelism: 6
- targets:
- "*"
run-on:
+7
View File
@@ -3,3 +3,10 @@ nx-dev/**/jest.config.js
_files
_solution
nx-dev/tutorial/**/templates
# Generated by napi-rs (outputs of build-native)
packages/nx/src/native/index.d.ts
packages/nx/src/native/native-bindings.js
# Workaround for ignore-files crate bug with prefix matching
**/target/
+2 -11
View File
@@ -2,19 +2,10 @@
We would love for you to contribute to Nx! Read this document to see how to do it.
## How to Get Started Video
Watch this 5-minute video:
<a href="https://www.youtube.com/watch?v=8LCA_4qxc08" target="_blank" rel="noreferrer">
<p style="text-align: center;"><img src="./images/how-to-contribute.png" width="600" alt="Nx - How to contribute"></p>
</a>
## Got a Question?
We are trying to keep GitHub issues for bug reports and feature requests. Using the `nrwl` tag
on [Stack Overflow](https://stackoverflow.com/questions/tagged/nrwl) is a much better place to ask general questions
about how to use Nx.
We are trying to keep GitHub issues for bug reports and feature requests.
You can join our [Discord](https://go.nx.dev/community) for general questions and seeking help from others.
## Found an Issue?
Generated
+26 -510
View File
@@ -260,15 +260,6 @@ dependencies = [
"wyz",
]
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]]
name = "bstr"
version = "1.12.1"
@@ -276,7 +267,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab"
dependencies = [
"memchr",
"regex-automata",
"serde",
]
@@ -314,12 +304,6 @@ version = "1.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "byteorder-lite"
version = "0.1.0"
@@ -513,15 +497,6 @@ version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "cpufeatures"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
dependencies = [
"libc",
]
[[package]]
name = "crc32fast"
version = "1.5.0"
@@ -616,16 +591,6 @@ version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
[[package]]
name = "crypto-common"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "ctor"
version = "0.2.9"
@@ -721,16 +686,6 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
]
[[package]]
name = "dispatch2"
version = "0.3.0"
@@ -803,12 +758,6 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
[[package]]
name = "endian-type"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "869b0adbda23651a9c5c0c3d270aac9fcb52e8622a8f2b17e57802d7791962f2"
[[package]]
name = "env_filter"
version = "0.1.4"
@@ -874,16 +823,6 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
[[package]]
name = "faster-hex"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7223ae2d2f179b803433d9c830478527e92b8117eab39460edae7f1614d9fb73"
dependencies = [
"heapless",
"serde",
]
[[package]]
name = "fastrand"
version = "2.3.0"
@@ -1131,16 +1070,6 @@ dependencies = [
"slab",
]
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "gethostname"
version = "1.1.0"
@@ -1184,244 +1113,6 @@ version = "0.32.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7"
[[package]]
name = "gix-actor"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5f79dc4dca964c163419ad50a63552171b3597b804f9de6a96779b207b4d710"
dependencies = [
"bstr",
"gix-date",
"gix-utils",
"itoa",
"thiserror 2.0.18",
"winnow",
]
[[package]]
name = "gix-config"
version = "0.50.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b58e2ff8eef96b71f2c5e260f02ca0475caff374027c5cc5a29bda69fac67404"
dependencies = [
"bstr",
"gix-config-value",
"gix-features",
"gix-glob",
"gix-path",
"gix-ref",
"gix-sec",
"memchr",
"smallvec",
"thiserror 2.0.18",
"unicode-bom",
"winnow",
]
[[package]]
name = "gix-config-value"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2409cffa4fe8b303847d5b6ba8df9da9ba65d302fc5ee474ea0cac5afde79840"
dependencies = [
"bitflags 2.10.0",
"bstr",
"gix-path",
"libc",
"thiserror 2.0.18",
]
[[package]]
name = "gix-date"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa1dcfa6042b334f049c2e717ae816806272a7801b13ff2eadad3f069d7b4a85"
dependencies = [
"bstr",
"itoa",
"jiff",
"smallvec",
"thiserror 2.0.18",
]
[[package]]
name = "gix-features"
version = "0.45.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d56aad357ae016449434705033df644ac6253dfcf1281aad3af3af9e907560d1"
dependencies = [
"gix-path",
"gix-trace",
"gix-utils",
"libc",
"prodash",
"walkdir",
]
[[package]]
name = "gix-fs"
version = "0.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "785b9c499e46bc78d7b81c148c21b3fca18655379ee729a856ed19ce50d359ec"
dependencies = [
"bstr",
"fastrand",
"gix-features",
"gix-path",
"gix-utils",
"thiserror 2.0.18",
]
[[package]]
name = "gix-glob"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8546300aee4c65c5862c22a3e321124a69b654a61a8b60de546a9284812b7e2"
dependencies = [
"bitflags 2.10.0",
"bstr",
"gix-features",
"gix-path",
]
[[package]]
name = "gix-hash"
version = "0.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e153930f42ccdab8a3306b1027cd524879f6a8996cd0c474d18b0e56cae7714d"
dependencies = [
"faster-hex",
"gix-features",
"sha1-checked",
"thiserror 2.0.18",
]
[[package]]
name = "gix-hashtable"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "222f7428636020bef272a87ed833ea48bf5fb3193f99852ae16fbb5a602bd2f0"
dependencies = [
"gix-hash",
"hashbrown 0.16.1",
"parking_lot",
]
[[package]]
name = "gix-lock"
version = "20.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "115268ae5e3b3b7bc7fc77260eecee05acca458e45318ca45d35467fa81a3ac5"
dependencies = [
"gix-tempfile",
"gix-utils",
"thiserror 2.0.18",
]
[[package]]
name = "gix-object"
version = "0.54.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "283df1e0c2b00f099683f2dd4bb3e2552ce87a46fcdd1ca2ac35e387a2d67136"
dependencies = [
"bstr",
"gix-actor",
"gix-date",
"gix-features",
"gix-hash",
"gix-hashtable",
"gix-path",
"gix-utils",
"gix-validate",
"itoa",
"smallvec",
"thiserror 2.0.18",
"winnow",
]
[[package]]
name = "gix-path"
version = "0.10.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cb06c3e4f8eed6e24fd915fa93145e28a511f4ea0e768bae16673e05ed3f366"
dependencies = [
"bstr",
"gix-trace",
"gix-validate",
"thiserror 2.0.18",
]
[[package]]
name = "gix-ref"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccb33aa97006e37e9e83fde233569a66b02ed16fd4b0406cdf35834b06cf8a63"
dependencies = [
"gix-actor",
"gix-features",
"gix-fs",
"gix-hash",
"gix-lock",
"gix-object",
"gix-path",
"gix-tempfile",
"gix-utils",
"gix-validate",
"memmap2",
"thiserror 2.0.18",
"winnow",
]
[[package]]
name = "gix-sec"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea9962ed6d9114f7f100efe038752f41283c225bb507a2888903ac593dffa6be"
dependencies = [
"bitflags 2.10.0",
"gix-path",
"libc",
"windows-sys 0.61.2",
]
[[package]]
name = "gix-tempfile"
version = "20.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad89218e74850f42d364ed3877c7291f0474c8533502df91bb877ecc5cb0dd40"
dependencies = [
"gix-fs",
"libc",
"parking_lot",
"tempfile",
]
[[package]]
name = "gix-trace"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e42a4c2583357721ba2d887916e78df504980f22f1182df06997ce197b89504"
[[package]]
name = "gix-utils"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "befcdbdfb1238d2854591f760a48711bed85e72d80a10e8f2f93f656746ef7c5"
dependencies = [
"fastrand",
"unicode-normalization",
]
[[package]]
name = "gix-validate"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b1e63a5b516e970a594f870ed4571a8fdcb8a344e7bd407a20db8bd61dbfde4"
dependencies = [
"bstr",
"thiserror 2.0.18",
]
[[package]]
name = "globset"
version = "0.4.18"
@@ -1476,15 +1167,6 @@ dependencies = [
"zerocopy",
]
[[package]]
name = "hash32"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606"
dependencies = [
"byteorder",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
@@ -1532,16 +1214,6 @@ dependencies = [
"hashbrown 0.14.5",
]
[[package]]
name = "heapless"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad"
dependencies = [
"hash32",
"stable_deref_trait",
]
[[package]]
name = "heck"
version = "0.5.0"
@@ -1798,25 +1470,6 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "ignore-files"
version = "3.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3b0030836e50229b1c47a6604ea95268b164492d6104d79989179a02255254f"
dependencies = [
"dunce",
"futures",
"gix-config",
"ignore",
"miette",
"normalize-path",
"project-origins",
"radix_trie",
"thiserror 2.0.18",
"tokio",
"tracing",
]
[[package]]
name = "image"
version = "0.25.9"
@@ -1977,47 +1630,6 @@ version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
[[package]]
name = "jiff"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49"
dependencies = [
"jiff-static",
"jiff-tzdb-platform",
"log",
"portable-atomic",
"portable-atomic-util",
"serde",
"windows-sys 0.59.0",
]
[[package]]
name = "jiff-static"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.114",
]
[[package]]
name = "jiff-tzdb"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68971ebff725b9e2ca27a601c5eb38a4c5d64422c4cbab0c535f248087eda5c2"
[[package]]
name = "jiff-tzdb-platform"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8"
dependencies = [
"jiff-tzdb",
]
[[package]]
name = "jni"
version = "0.21.1"
@@ -2280,15 +1892,6 @@ version = "2.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
[[package]]
name = "memmap2"
version = "0.9.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "744133e4a0e0a658e1374cf3bf8e415c4052a15a111acd372764c55b4177d490"
dependencies = [
"libc",
]
[[package]]
name = "memoffset"
version = "0.6.5"
@@ -2424,15 +2027,6 @@ version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
[[package]]
name = "nibble_vec"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43"
dependencies = [
"smallvec",
]
[[package]]
name = "nix"
version = "0.25.1"
@@ -2585,7 +2179,6 @@ dependencies = [
"globset",
"hashbrown 0.14.5",
"ignore",
"ignore-files",
"insta",
"interprocess",
"itertools 0.10.5",
@@ -2610,6 +2203,7 @@ dependencies = [
"serde",
"serde_json",
"static_assertions",
"static_vcruntime",
"swc_common",
"swc_ecma_ast",
"swc_ecma_dep_graph",
@@ -2632,9 +2226,9 @@ dependencies = [
"walkdir",
"watchexec",
"watchexec-events",
"watchexec-filterer-ignore",
"watchexec-signals",
"winapi",
"winres",
"wrap-ansi",
"xxhash-rust",
]
@@ -2881,21 +2475,6 @@ dependencies = [
"miniz_oxide",
]
[[package]]
name = "portable-atomic"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
[[package]]
name = "portable-atomic-util"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a9db96d7fa8782dd8c15ce32ffe8680bbd1e978a43bf51a34d39483540495f5"
dependencies = [
"portable-atomic",
]
[[package]]
name = "portable-pty"
version = "0.8.1"
@@ -3005,26 +2584,6 @@ dependencies = [
"windows 0.62.2",
]
[[package]]
name = "prodash"
version = "30.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a6efc566849d3d9d737c5cb06cc50e48950ebe3d3f9d70631490fff3a07b139"
dependencies = [
"parking_lot",
]
[[package]]
name = "project-origins"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e42382141d102db809df94324b513c388b047ebc47926eec5417623b88781527"
dependencies = [
"futures",
"tokio",
"tokio-stream",
]
[[package]]
name = "psm"
version = "0.1.29"
@@ -3155,16 +2714,6 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
[[package]]
name = "radix_trie"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b4431027dcd37fc2a73ef740b5f233aa805897935b8bce0195e41bbf9a3289a"
dependencies = [
"endian-type",
"nibble_vec",
]
[[package]]
name = "rand"
version = "0.8.5"
@@ -3698,27 +3247,6 @@ dependencies = [
"serial-core",
]
[[package]]
name = "sha1"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "sha1-checked"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89f599ac0c323ebb1c6082821a54962b839832b03984598375bff3975b804423"
dependencies = [
"digest",
"sha1",
]
[[package]]
name = "sharded-slab"
version = "0.1.7"
@@ -3869,6 +3397,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "static_vcruntime"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff7589a1859b09232522bb9edf076ca7fcf14ded96685d3fa629db73023ffbb7"
[[package]]
name = "string-width"
version = "0.1.0"
@@ -4415,6 +3949,15 @@ dependencies = [
"tokio",
]
[[package]]
name = "toml"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
dependencies = [
"serde",
]
[[package]]
name = "toml_datetime"
version = "0.7.0"
@@ -4642,18 +4185,6 @@ version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a"
[[package]]
name = "typenum"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
[[package]]
name = "unicode-bom"
version = "2.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7eec5d1121208364f6793f7d2e222bf75a915c19557537745b195b253dd64217"
[[package]]
name = "unicode-id"
version = "0.3.6"
@@ -4666,15 +4197,6 @@ version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
[[package]]
name = "unicode-normalization"
version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8"
dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-segmentation"
version = "1.12.0"
@@ -4929,21 +4451,6 @@ dependencies = [
"watchexec-signals",
]
[[package]]
name = "watchexec-filterer-ignore"
version = "7.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "923b0345fd40893ec39caf41ef2f4ce999b1bf25338001d211719f48ee7d7da4"
dependencies = [
"dunce",
"ignore",
"ignore-files",
"normalize-path",
"tracing",
"watchexec",
"watchexec-events",
]
[[package]]
name = "watchexec-signals"
version = "5.0.1"
@@ -5579,6 +5086,15 @@ dependencies = [
"winapi",
]
[[package]]
name = "winres"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b68db261ef59e9e52806f688020631e987592bd83619edccda9c47d42cde4f6c"
dependencies = [
"toml",
]
[[package]]
name = "wit-bindgen"
version = "0.51.0"
+1 -1
View File
@@ -1,6 +1,6 @@
(The MIT License)
Copyright (c) 2017-2025 Narwhal Technologies Inc.
Copyright (c) 2017-2026 Narwhal Technologies Inc.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
+1 -3
View File
@@ -19,9 +19,7 @@
<hr>
# Smart Monorepos · Fast Builds
Get to green PRs in half the time. Nx optimizes your builds, scales your CI, and fixes failed PRs. Built for developers and AI agents.
# The Monorepo Platform that amplifies both developers and AI agents. Nx optimizes your builds, scales your CI, and fixes failed PRs automatically. Ship in half the time.
Create a new Nx workspace with
+12
View File
@@ -13,3 +13,15 @@ Instead, please report them to the Security Team at security@nrwl.io.
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message.
Nx follows the principle of Coordinated Vulnerability Disclosure.
## What Should Be Reported
The security email is for **demonstrable, verified vulnerabilities within the Nx codebase itself**.
**Please do not use the security email for:**
- Reports about outdated dependencies (e.g., "package X has a newer version available")
- Reports about dependencies with known CVEs that do not directly affect Nx functionality
- General vulnerability scanner output
If you have a concern about an outdated dependency that you believe impacts Nx users, please open a [GitHub issue](https://github.com/nrwl/nx/issues/new/choose) instead.
+388
View File
@@ -0,0 +1,388 @@
# Nx Documentation Style Guide
This document defines the standards for Nx documentation on nx.dev, including voice, grammar, formatting, and terminology.
For automated enforcement, see the [Vale configuration](#vale-configuration) section.
## Information architecture
When creating or reorganizing documentation, follow these five principles to determine where content belongs.
### 1. Progressive disclosure (the "journey" rule)
Don't overwhelm the user. Reveal complexity only as they advance in their journey.
**The test:** Is this for the first 30 minutes (Getting Started), the first 30 days (Features), or forever (Reference)?
### 2. Category homogeneity (the "scan" rule)
Items in a list must be of the same "type" (noun, verb, or concept) to reduce cognitive load.
**The test:** Does this list mix concepts (mental model), tasks (update Nx), and products (React)? If yes, split it.
### 3. Type-based navigation (the "intent" rule)
Separate learning (narrative/guides) from looking up (reference/API).
**The test:** Is the user here to learn a workflow (guide) or look up a flag syntax (reference)?
### 4. The pen and paper test (the "theory" rule)
Distinguish architecture from features to keep "core concepts" pure.
**The test:** Can I explain this using only a pen and paper?
- Yes: It goes in **How Nx Works** (architecture).
- No (I need a terminal): It goes in **Platform Features** (feature).
### 5. Universal vs. specific (the "placement" rule)
Distinguish platform features from ecosystem tools to prevent "Features" from becoming a junk drawer.
**The test:** Does this feature apply to every user (e.g., caching, Nx Agents)?
- Yes: **Platform Features**.
- No (only React users): **Technologies**.
### Sidebar structure
The sidebar has four top-level sections that follow the user journey:
1. **Getting Started** - Essential setup, tutorials, and core concepts (How Nx Works, Platform Features)
2. **Technologies** - Framework and tool-specific guides (React, Angular, Node, build tools, test tools)
3. **Knowledge Base** - Recipes, troubleshooting, and topic-specific guides
4. **Reference** - Exhaustive facts, no narrative (CLI commands, configuration, API docs)
## The Nx voice
Nx documentation is **direct, practical, and confident**. We write like a knowledgeable colleague pairing with you — not like a textbook, not like a marketing page, and not like a chatbot.
The voice should be:
- **Conversational but efficient.** Use contractions. Get to the point. Don't pad sentences.
- **Second person.** Write "you" — address the reader directly.
- **Action-oriented.** Lead with what the reader can _do_, not what Nx _is_.
- **Honest about tradeoffs.** Don't oversell. If something has limitations, say so.
### Voice do's and don'ts
| Do | Don't |
| ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------- |
| "You can speed up builds by enabling remote caching." | "Nx allows you to speed up builds." |
| "Run `nx build` to build your project." | "In order to build your project, you can run the `nx build` command." |
| "This works best with fewer than 50 projects." | "This feature can easily scale to any number of projects." |
| "Nx reads your `vite.config.ts` and infers build targets automatically." | "Nx provides a robust and comprehensive mechanism for inferring build targets." |
| "If the cache is stale, delete `.nx/cache` and retry." | "Should you encounter issues with caching, you may want to consider clearing your cache directory." |
### Anti-AI language
Documentation must not read like it was generated by an AI assistant. Even when AI tools are used in the writing process, the output must be edited to sound like a human wrote it.
**Never use these phrases:**
- "It's important to note that..."
- "It's worth noting that..." / "It should be noted that..."
- "In this section, we will explore..."
- "Let's dive into..." / "Let's take a closer look at..."
- "Whether you're a beginner or an experienced developer..."
- "In today's fast-paced development environment..."
- "Unlock the power of..." / "Harness the power of..."
- "Take your workspace to the next level"
- "Streamline your workflow" (as a generic claim without specifics)
- "This comprehensive guide will..."
- "Without further ado..."
- "In conclusion..." / "To summarize..." / "As we've seen..."
- "Game-changer" / "Cutting-edge" / "Groundbreaking"
- "Seamless" / "Seamlessly" (unless describing an actual integration)
**Avoid hedging words unless genuinely needed:**
- "Essentially" / "Basically" / "Effectively"
- "Generally speaking"
- "It is worth mentioning"
- "Arguably"
- "Needless to say"
- "As a matter of fact"
**Watch for AI-style sentence patterns:**
- Sentences that start with "This allows you to..." or "This enables you to..." — rewrite to lead with the reader's action.
- Paragraphs that start with a general claim and then restate it slightly differently. Say it once.
- Excessive use of "robust", "leverage", "utilize", "facilitate", "comprehensive", "aforementioned."
- Lists where every item starts with the same grammatical structure repeated 5+ times with slight variation. Vary your phrasing.
### Self-referential writing
Don't write about the document itself.
Do:
- "Nx uses a project graph to determine task dependencies."
Don't:
- "This page explains how Nx uses a project graph."
- "In this guide, we'll walk through..."
- "This document covers..."
Get right to the point. The reader already knows they're on a page — they want the information.
### Building trust
Don't use filler words that undermine the reader's trust.
- Don't use "easily", "simply", "just", or "straightforward" — if something were truly simple, you wouldn't need to document it. These words also make readers feel bad when they struggle.
- Don't use marketing language: "This feature will save you hours" or "Nx makes CI effortless."
- Be specific instead: "Remote caching can reduce CI times from 45 minutes to under 5 minutes for cache-hit builds."
### Customer perspective
Focus on what the reader can do, not what Nx does.
Do:
- "Use `nx affected` to run tasks only for projects impacted by your changes."
Don't:
- "Nx allows you to run affected tasks."
- "Nx provides the ability to run tasks selectively."
Words like "allow" and "enable" are signals you're writing from the product's perspective instead of the reader's.
## Language
Write in US English.
### Active voice
Use active voice in most cases.
Do: "Nx caches the build output."
Don't: "The build output is cached by Nx."
Exception: When "Nx" as the subject sounds awkward, passive voice is fine. "The output is stored in `.nx/cache`" is better than "Nx stores the output in `.nx/cache`" if Nx isn't the focus of the sentence.
### Contractions
Use contractions. They make the text feel natural.
- "You'll need to configure..." not "You will need to configure..."
- "It doesn't support..." not "It does not support..."
Don't contract for emphasis in warnings or error descriptions:
- "**Do not** delete the `nx.json` file."
- "Requests to localhost **are not** allowed."
Don't contract proper nouns: "the Vite plugin is..." not "Vite's a plugin..."
### Capitalization
Use sentence case for headings. Capitalize proper nouns only.
- `# Use remote caching to speed up CI`
- `## Configure the Vite plugin`
Feature names are lowercase unless they are a proper product name:
| Correct | Incorrect |
| -------------- | -------------- |
| remote caching | Remote Caching |
| task pipeline | Task Pipeline |
| project graph | Project Graph |
| Nx Cloud | nx cloud |
| Nx Console | nx console |
| Nx Agents | nx agents |
| Nx Replay | nx replay |
### Acronyms
Spell out acronyms on first use per page. Don't spell out widely-known ones: CI, CD, API, URL, CLI, PR, IDE.
Don't make acronyms plural with apostrophes. Use `APIs`, not `API's`.
### Numbers
Spell out zero through nine. Use numerals for 10 and above. Always use numerals with units: "5 minutes", "3 projects."
### Possessives
Don't use possessives on product names. "the Docker CLI", not "Docker's CLI." "the Nx configuration", not "Nx's configuration."
## Text
### Headings
- Don't skip heading levels (e.g., `##` to `####`).
- Don't use code in headings unless it's essential (like a CLI command).
- Don't use bold text in headings.
- Keep headings short and scannable. Lead with keywords.
### Line length
- Wrap lines at approximately 100 characters for readability in diffs.
- Start each new sentence on a new line.
- Exception: Don't break links across lines.
### Punctuation
- Use serial (Oxford) commas: "React, Angular, and Vue."
- Use one space between sentences.
- Don't use semicolons. Use two sentences instead.
- Don't use em dashes or en dashes. Use commas or separate sentences.
### Placeholder text
Use `<` and `>` for values the reader must replace:
```shell
nx run <project-name>:build
```
If the placeholder is inline, wrap it in a single backtick: `<your-project>`.
### Bold
Use bold for:
- UI elements: "Select **Add Connection**."
- Navigation paths: "Go to **Settings** > **Workspace**."
Don't use bold for emphasis or keywords. If you need emphasis, rewrite the sentence to be clearer.
### Inline code
Use inline code (single backticks) for:
- Commands and CLI arguments: `nx build`, `--parallel`
- File names and paths: `nx.json`, `.nx/cache`
- Configuration keys: `targetDefaults`, `namedInputs`
- Short outputs and values: `true`, `false`, `success`
### Code blocks
Use triple backticks with a language identifier:
````markdown
```json
{
"targetDefaults": {
"build": {
"cache": true
}
}
}
```
````
- Always specify a syntax language. Use `plaintext` if nothing else fits.
- Add a blank line before and after code blocks.
- For long config files, show only the relevant section and use comments to indicate omitted parts:
```json
{
// ... other config
"targetDefaults": {
"build": {
"cache": true
}
}
}
```
## Links
Links help readers find related information, but too many links make text hard to read.
### General rules
- Don't duplicate links. If you link to a page once, don't link to it again on the same page.
- Don't use links in headings.
- Avoid more than 15 links to other pages on any single page.
- Avoid multiple links in a single paragraph when possible.
### Link text
Use descriptive text, not "here" or "this page."
Do:
- "For more information, see [remote caching](/features/cache)."
- "To configure task pipelines, see [task pipeline configuration](/concepts/task-pipeline-configuration)."
Don't:
- "For more information, see [this page](/features/cache)."
- "Click [here](/features/cache) to learn more."
- "For more information, see the [Remote Caching](/features/cache) documentation."
Standard patterns:
- `For more information, see [link text](url).`
- `To <do this thing>, see [link text](url).`
### External links
Minimize external links. They break over time and are hard to maintain. When you must link externally, prefer official documentation (e.g., Vite docs, Webpack docs) over blog posts or third-party guides.
## Lists
- Use ordered lists for sequences of steps.
- Use unordered lists when order doesn't matter.
- Use dashes (`-`) for unordered lists.
- Start ordered list items with `1.` (Markdown auto-increments).
- Make list items parallel in structure.
- Add a colon after the introductory phrase.
- Don't use list items to complete an introductory sentence.
Do:
```markdown
You can clear the cache in the following ways:
- Delete the `.nx/cache` directory manually.
- Run `nx reset` to clear all cached results.
```
Don't:
```markdown
You can clear the cache by:
- Deleting the `.nx/cache` directory manually.
- Running `nx reset`.
```
## Tables
Use tables for structured data that benefits from a matrix layout. For simple lists of items with descriptions, use a regular list instead.
- Don't leave cells empty. Use "N/A" or "None."
- Use sentence case for headers.
- Keep the header and delimiter rows the same length.
## Nx-specific terminology
Use these terms consistently. When writing about Nx concepts, use the exact term from this list.
| Term | Usage notes |
| -------------- | ------------------------------------------------------------------------------------------------- |
| workspace | The root directory managed by Nx. Not "repo" or "monorepo" when referring to Nx's context. |
| project | An app or library within the workspace. |
| target | A task that can be run for a project (e.g., `build`, `test`, `lint`). |
| executor | The implementation behind a target. Not "builder." |
| generator | Code scaffolding tool. Not "schematic." |
| plugin | An Nx plugin that provides executors, generators, or graph inference. |
| task | A specific invocation of a target for a project (e.g., `myapp:build`). |
| task pipeline | The dependency graph between tasks. Not "task orchestration" or "task graph" in user-facing docs. |
| project graph | The dependency graph between projects. |
| affected | Projects impacted by a code change. |
| cache / cached | Not "memoized" or "stored results." |
| remote caching | Sharing cached results across machines. Specific product: "Nx Replay." |
| Nx Cloud | The hosted CI/CD product. Always capitalized. |
| Nx Console | The IDE extension. Always capitalized. |
| Nx Agents | Distributed task execution product. Always capitalized. |
| Nx Replay | Remote caching product. Always capitalized. |
| `nx.json` | Always in code style. |
| `project.json` | Always in code style. |
+5 -19
View File
@@ -7,14 +7,16 @@ import markdoc from '@astrojs/markdoc';
import tailwindcss from '@tailwindcss/vite';
import { sidebar } from './sidebar.mts';
import rehypeTableOptionLinks from './src/plugins/utils/rehype-table-option-links.ts';
import { resolveNxDevUrl } from './src/utils/resolve-nx-dev-url.ts';
// Always resolve NX_DEV_URL so downstream consumers (Footer, Header) pick it up.
// For deploy previews this overrides any site-level env var to point to the matching preview.
process.env.NX_DEV_URL = resolveNxDevUrl();
const BASE = '/docs';
// This is exposed as window.__CONFIG
const PUBLIC_CONFIG = {
cookiebotDisabled: process.env.COOKIEBOT_DISABLED === 'true',
cookiebotId: process.env.COOKIEBOT_ID ?? null,
gaMeasurementId: 'UA-88380372-10',
gtmMeasurementId: 'GTM-KW8423B6',
isProd: process.env.NODE_ENV === 'production',
};
@@ -60,22 +62,6 @@ export default defineConfig({
tag: 'script',
content: `window.__CONFIG = ${JSON.stringify(PUBLIC_CONFIG)};`,
},
...(process.env.COOKIEBOT_ID &&
process.env.COOKIEBOT_DISABLED !== 'true'
? [
{
/** @type {"script"} */
tag: 'script',
attrs: {
id: 'Cookiebot',
src: 'https://consent.cookiebot.com/uc.js',
'data-cbid': process.env.COOKIEBOT_ID,
'data-blockingmode': 'auto',
type: 'text/javascript',
},
},
]
: []),
{
tag: 'script',
attrs: {
@@ -0,0 +1,129 @@
import { test, expect } from '@playwright/test';
test.describe('CLI sub-command formatting', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/docs/reference/nx-commands');
await expect(
page.getByRole('heading', { name: 'Nx Commands' })
).toBeVisible();
});
test('parent commands render as h2 and sub-commands as h3', async ({
page,
}) => {
const mainContent = page.getByTestId('main-pane');
// "nx show" should be an h2 (top-level parent command)
const showHeading = mainContent.getByRole('heading', {
name: 'nx show',
level: 2,
exact: true,
});
await expect(showHeading).toBeVisible();
// "nx show projects" should be an h3 (sub-command nested under parent)
const showProjectsHeading = mainContent.getByRole('heading', {
name: 'nx show projects',
level: 3,
exact: true,
});
await expect(showProjectsHeading).toBeVisible();
// "nx show project" should also be an h3
const showProjectHeading = mainContent.getByRole('heading', {
name: 'nx show project',
level: 3,
exact: true,
});
await expect(showProjectHeading).toBeVisible();
});
test('sub-command usage blocks show the full command name', async ({
page,
}) => {
const mainContent = page.getByTestId('main-pane');
// Find the "nx show projects" section and verify its usage block
// The usage code block should contain "nx show projects", not "nx projects"
const showProjectsHeading = mainContent.getByRole('heading', {
name: 'nx show projects',
level: 3,
exact: true,
});
await expect(showProjectsHeading).toBeVisible();
// Get the section between "nx show projects" heading and the next heading.
// We look for a code block containing the correct usage pattern.
const codeBlocks = mainContent.locator('pre code');
const allCodeTexts = await codeBlocks.allTextContents();
// There should be a usage block with "nx show projects" (full sub-command name)
expect(allCodeTexts.some((text) => text.includes('nx show projects'))).toBe(
true
);
// There should NOT be a usage block with just "nx projects" (missing parent)
expect(
allCodeTexts.some(
(text) => text.match(/^nx projects/) || text.match(/\nnx projects/)
)
).toBe(false);
});
test('release sub-commands use correct heading and usage format', async ({
page,
}) => {
const mainContent = page.getByTestId('main-pane');
// "nx release" should be h2
const releaseHeading = mainContent.getByRole('heading', {
name: 'nx release',
level: 2,
exact: true,
});
await expect(releaseHeading).toBeVisible();
// "nx release version" should be h3
const releaseVersionHeading = mainContent.getByRole('heading', {
name: 'nx release version',
level: 3,
exact: true,
});
await expect(releaseVersionHeading).toBeVisible();
// Verify usage block includes the full command
const codeBlocks = mainContent.locator('pre code');
const allCodeTexts = await codeBlocks.allTextContents();
expect(
allCodeTexts.some((text) => text.includes('nx release version'))
).toBe(true);
});
test('options and examples are h4 headings excluded from the TOC', async ({
page,
}) => {
const mainContent = page.getByTestId('main-pane');
// Options/Examples should be h4 headings — linkable but below the TOC threshold (h2-h3)
const sharedOptionsHeading = mainContent.getByRole('heading', {
name: 'Shared Options',
level: 4,
});
await expect(sharedOptionsHeading.first()).toBeVisible();
const optionsHeading = mainContent.getByRole('heading', {
name: 'Options',
level: 4,
});
await expect(optionsHeading.first()).toBeVisible();
// They should NOT appear as h2 or h3 (which would put them in the TOC)
await expect(
mainContent.getByRole('heading', { name: 'Options', level: 2 })
).toHaveCount(0);
await expect(
mainContent.getByRole('heading', { name: 'Options', level: 3 })
).toHaveCount(0);
});
});
+9
View File
@@ -244,6 +244,15 @@ export default defineMarkdocConfig({
},
},
},
sidebar_group_cards: {
render: component('./src/components/markdoc/SidebarGroupCards.astro'),
attributes: {
group: {
type: 'String',
required: true,
},
},
},
metrics: {
render: component('./src/components/markdoc/Metrics.astro'),
attributes: {
@@ -33,9 +33,19 @@ async function sendToGA4(
const clientId = getClientId(request);
const userAgent = request.headers.get('user-agent') || 'unknown';
// Detect AI tools from user agent
// Anthropic: ClaudeBot (training), Claude-User (user fetch), Claude-SearchBot (search index),
// Claude-Web (web crawler), anthropic-ai (legacy training)
// OpenAI: GPTBot (training), ChatGPT-User (user browsing), OAI-SearchBot (search index)
// Perplexity: PerplexityBot (search index), Perplexity-User (user fetch)
// Google: Google-Extended (AI/Gemini training)
// Other: Bytespider (ByteDance training)
const isAITool =
/bot|crawler|spider|gpt|claude|anthropic|openai|perplexity|cohere/i.test(
/ClaudeBot|Claude-User|Claude-SearchBot|Claude-Web|anthropic-ai|GPTBot|ChatGPT-User|OAI-SearchBot|PerplexityBot|Perplexity-User|Google-Extended|Bytespider/i.test(
userAgent
);
// Generic bots (SEO crawlers, social previews, etc.)
const isGenericBot =
/Googlebot|Amazonbot|CCBot|BingBot|YandexBot|DuckDuckBot|Applebot|crawler|spider|slurp|facebook|twitter|linkedin|slack|discord|telegram/i.test(
userAgent
);
@@ -55,6 +65,7 @@ async function sendToGA4(
file_extension: pathname.substring(pathname.lastIndexOf('.')),
user_agent: userAgent,
is_ai_tool: isAITool ? 'true' : 'false',
is_bot: isGenericBot ? 'true' : 'false',
country: context.geo?.country?.code || 'unknown',
},
},
@@ -26,8 +26,19 @@ async function sendToGA4(
const clientId = getClientId(request);
const userAgent = request.headers.get('user-agent') || 'unknown';
// Anthropic: ClaudeBot (training), Claude-User (user fetch), Claude-SearchBot (search index),
// Claude-Web (web crawler), anthropic-ai (legacy training)
// OpenAI: GPTBot (training), ChatGPT-User (user browsing), OAI-SearchBot (search index)
// Perplexity: PerplexityBot (search index), Perplexity-User (user fetch)
// Google: Google-Extended (AI/Gemini training)
// Other: Bytespider (ByteDance training)
const isAITool =
/bot|crawler|spider|gpt|claude|anthropic|openai|perplexity|cohere/i.test(
/ClaudeBot|Claude-User|Claude-SearchBot|Claude-Web|anthropic-ai|GPTBot|ChatGPT-User|OAI-SearchBot|PerplexityBot|Perplexity-User|Google-Extended|Bytespider/i.test(
userAgent
);
// Generic bots (SEO crawlers, social previews, etc.)
const isGenericBot =
/Googlebot|Amazonbot|CCBot|BingBot|YandexBot|DuckDuckBot|Applebot|crawler|spider|slurp|facebook|twitter|linkedin|slack|discord|telegram/i.test(
userAgent
);
@@ -44,6 +55,7 @@ async function sendToGA4(
file_extension: '.html',
user_agent: userAgent,
is_ai_tool: isAITool ? 'true' : 'false',
is_bot: isGenericBot ? 'true' : 'false',
country: context.geo?.country?.code || 'unknown',
},
},
+10 -118
View File
@@ -38,31 +38,9 @@
const config = window.__CONFIG || {};
if (!config.isProd) return;
const isCookiebotDisabled = config.cookiebotDisabled ?? false;
const gaMeasurementId = config.gaMeasurementId ?? 'UA-88380372-10';
const gtmMeasurementId = config.gtmMeasurementId ?? 'GTM-KW8423B6';
// Initialize global objects
window.Cookiebot = window.Cookiebot || {};
window.dataLayer = window.dataLayer || [];
window.gtag =
window.gtag ||
function () {
window.dataLayer.push(arguments);
};
const loadGoogleAnalytics = () => {
const script = document.createElement('script');
script.src = `https://www.googletagmanager.com/gtag/js?id=${gaMeasurementId}`;
script.async = true;
document.head.appendChild(script);
// Initialize gtag
window.gtag('js', new Date());
window.gtag('config', gaMeasurementId, {
page_path: window.location.pathname,
});
};
const loadGTM = () => {
if (!gtmMeasurementId) return;
@@ -79,69 +57,9 @@
})(window, document, 'script', 'dataLayer', gtmMeasurementId);
};
const loadHubSpot = () => {
const hsScript = document.createElement('script');
hsScript.src = 'https://js.hs-scripts.com/2757427.js';
hsScript.async = true;
hsScript.defer = true;
document.head.appendChild(hsScript);
// Load HubSpot Forms
const hsFormsScript = document.createElement('script');
hsFormsScript.src = '//js.hsforms.net/forms/v2.js';
hsFormsScript.async = true;
hsFormsScript.defer = true;
document.head.appendChild(hsFormsScript);
};
const loadApollo = () => {
const n = Math.random().toString(36).substring(7);
const script = document.createElement('script');
script.src = `https://assets.apollo.io/micro/website-tracker/tracker.iife.js?nocache=${n}`;
script.async = true;
script.defer = true;
script.onload = function () {
if (window.trackingFunctions?.onLoad) {
window.trackingFunctions.onLoad({
appId: '65e1db2f1976f30300fd8b26',
});
}
};
document.head.appendChild(script);
};
const loadHotjar = () => {
(function (h, o, t, j, a, r) {
h.hj =
h.hj ||
function () {
(h.hj.q = h.hj.q || []).push(arguments);
};
h._hjSettings = { hjid: 2774127, hjsv: 6 };
a = o.getElementsByTagName('head')[0];
r = o.createElement('script');
r.async = 1;
r.src = t + h._hjSettings.hjid + j + h._hjSettings.hjsv;
a.appendChild(r);
})(window, document, 'https://static.hotjar.com/c/hotjar-', '.js?sv=');
};
const loadTwitterPixel = () => {
!(function (e, t, n, s, u, a) {
e.twq ||
((s = e.twq =
function () {
s.exe ? s.exe.apply(s, arguments) : s.queue.push(arguments);
}),
(s.version = '1.1'),
(s.queue = []),
(u = t.createElement(n)),
(u.async = !0),
(u.src = 'https://static.ads-twitter.com/uwt.js'),
(a = t.getElementsByTagName(n)[0]),
a.parentNode.insertBefore(u, a));
})(window, document, 'script');
window.twq('config', 'obtp4');
// GA4 events are dispatched via GTM dataLayer.
const pushGtmEvent = (eventName, payload) => {
window.dataLayer.push({ event: eventName, ...payload });
};
// Scroll depth tracking
@@ -223,8 +141,7 @@
let inputHandler = null;
function sendSearchEvent(eventType, data) {
if (typeof window.gtag !== 'undefined')
window.gtag('event', eventType, data);
pushGtmEvent(eventType, data);
}
function trackSearchQuery(query) {
@@ -275,33 +192,11 @@
});
}
const checkAndLoadScripts = () => {
if (isCookiebotDisabled) {
loadGoogleAnalytics();
loadGTM();
loadHubSpot();
setupSearchTracking();
setupScrollTracking();
} else if (window.Cookiebot && window.Cookiebot.consent) {
// Statistics cookies (Google Analytics, GTM, Search, Scroll Tracking)
if (window.Cookiebot.consent.statistics) {
loadGoogleAnalytics();
loadGTM();
setupSearchTracking();
setupScrollTracking();
}
// Marketing cookies (HubSpot, Apollo, Hotjar, Twitter)
if (window.Cookiebot.consent.marketing) {
loadHubSpot();
loadApollo();
loadHotjar();
loadTwitterPixel();
}
} else {
// Wait for Cookiebot to load
setTimeout(checkAndLoadScripts, 100);
}
const initializeAnalytics = () => {
if (!gtmMeasurementId) return;
loadGTM();
setupSearchTracking();
setupScrollTracking();
};
// Add GTM noscript iframe to body
@@ -318,11 +213,8 @@
document.body.insertBefore(noscript, document.body.firstChild);
};
// Listen for user consent to cookies
window.addEventListener('CookiebotOnAccept', checkAndLoadScripts);
// Initial check
checkAndLoadScripts();
initializeAnalytics();
// Add GTM noscript on DOM ready
if (document.readyState === 'loading') {
+21 -12
View File
@@ -3,6 +3,7 @@ import {
getTechnologyKBItems,
getTechnologyAPIItems,
} from './src/plugins/utils/plugin-mappings';
import { resolveNxDevUrl } from './src/utils/resolve-nx-dev-url';
type SidebarItems = NonNullable<StarlightUserConfig['sidebar']>;
@@ -24,8 +25,6 @@ const learnGroups: SidebarItems = [
items: [
{ label: 'Intro to Nx', link: 'getting-started/intro' },
{ label: 'Installation', link: 'getting-started/installation' },
{ label: 'Editor Setup', link: 'getting-started/editor-setup' },
{ label: 'AI Integrations', link: 'getting-started/ai-setup' },
{
label: 'Start a New Project',
link: 'getting-started/start-new-project',
@@ -34,6 +33,12 @@ const learnGroups: SidebarItems = [
label: 'Add to Existing Project',
link: 'getting-started/start-with-existing-project',
},
{ label: 'Editor Setup', link: 'getting-started/editor-setup' },
{ label: 'AI Integrations', link: 'getting-started/ai-setup' },
{
label: 'Nx Cloud',
link: 'getting-started/nx-cloud',
},
{
label: 'Tutorials',
collapsed: true,
@@ -88,6 +93,10 @@ const learnGroups: SidebarItems = [
link: 'concepts/ci-concepts/parallelization-distribution',
},
{ label: 'Nx Daemon', link: 'concepts/nx-daemon' },
{
label: 'Synthetic Monorepos',
link: 'concepts/synthetic-monorepos',
},
],
},
{
@@ -95,6 +104,10 @@ const learnGroups: SidebarItems = [
collapsed: false,
items: [
{ label: 'Run Tasks', link: 'features/run-tasks' },
{
label: 'Cache Task Results',
link: 'features/cache-task-results',
},
{ label: 'Enhance Your LLM', link: 'features/enhance-ai' },
{
label: 'Code Organization',
@@ -389,7 +402,7 @@ const technologiesGroups: SidebarItems = [
},
{
label: 'Angular Rsbuild',
link: 'technologies/angular/angular-rsbuild/create-config',
link: 'technologies/angular/angular-rsbuild/introduction',
},
{ label: 'React', link: 'technologies/react/introduction' },
{
@@ -886,6 +899,10 @@ const knowledgeBaseGroups: SidebarItems = [
label: 'TypeScript',
collapsed: true,
items: [
{
label: 'Maintain TypeScript Monorepos',
link: 'features/maintain-typescript-monorepos',
},
...getTechnologyKBItems('typescript'),
{
label: 'Buildable and Publishable Libraries',
@@ -895,10 +912,6 @@ const knowledgeBaseGroups: SidebarItems = [
label: 'TypeScript Project Linking',
link: 'concepts/typescript-project-linking',
},
{
label: 'Maintain TypeScript Monorepos',
link: 'features/maintain-typescript-monorepos',
},
],
},
{
@@ -997,10 +1010,6 @@ const referenceGroups: SidebarItems = [
{ label: 'nxignore', link: 'reference/nxignore' },
{ label: 'Glossary', link: 'reference/glossary' },
{ label: 'Releases', link: 'reference/releases' },
{
label: 'Node/TypeScript Compatibility',
link: 'reference/nodejs-typescript-compatibility',
},
{ label: 'Nx MCP', link: 'reference/nx-mcp' },
{ label: 'Nx Console Settings', link: 'reference/nx-console-settings' },
{ label: 'Nx Cloud CLI', link: 'reference/nx-cloud-cli' },
@@ -1155,7 +1164,7 @@ const referenceGroups: SidebarItems = [
},
{
label: 'Changelog',
link: `${process.env.NX_DEV_URL ?? 'https://nx.dev'}/changelog`,
link: `${resolveNxDevUrl()}/changelog`,
},
{
label: 'Deprecations',
@@ -0,0 +1,122 @@
<svg width="980" height="720" viewBox="0 0 980 720" fill="none" xmlns="http://www.w3.org/2000/svg">
<!-- Defs: arrow markers -->
<defs>
<marker id="arrowBlue" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto" markerUnits="strokeWidth">
<polygon points="0 0, 10 3.5, 0 7" fill="#476088"/>
</marker>
<marker id="arrowGreen" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto" markerUnits="strokeWidth">
<polygon points="0 0, 10 3.5, 0 7" fill="#70AF40"/>
</marker>
</defs>
<!-- Outer dotted border: Synthetic Monorepo boundary -->
<rect x="40" y="40" width="900" height="590" rx="24" ry="24"
stroke="#94A3B8" stroke-width="3" stroke-dasharray="12 6" fill="none"/>
<!-- "Synthetic Monorepo" label at bottom inside box -->
<text x="490" y="665" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="26" font-weight="700" fill="#94A3B8">Synthetic Monorepo</text>
<!-- ============================================ -->
<!-- Monorepo A (top-left): a rounded rect with 3 internal projects -->
<!-- ============================================ -->
<rect x="80" y="70" width="260" height="200" rx="16" ry="16"
stroke="#9CA3AF" stroke-width="2" fill="none"/>
<text x="210" y="100" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="14" font-weight="600" fill="#9CA3AF">Monorepo A</text>
<!-- App 1 (blue) -->
<circle cx="140" cy="165" r="38" fill="#476088"/>
<text x="140" y="161" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="600" fill="white">App 1</text>
<text x="140" y="178" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="11" fill="#CBD5E1">frontend</text>
<!-- Lib A (green) -->
<circle cx="270" cy="145" r="32" fill="#70AF40"/>
<text x="270" y="141" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="600" fill="white">Lib A</text>
<text x="270" y="157" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="11" fill="#E8F5E9">utils</text>
<!-- Lib B (green) -->
<circle cx="248" cy="222" r="28" fill="#70AF40"/>
<text x="248" y="218" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="12" font-weight="600" fill="white">Lib B</text>
<text x="248" y="233" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="10" fill="#E8F5E9">ui</text>
<!-- Internal arrows within Monorepo A -->
<line x1="175" y1="155" x2="238" y2="143" stroke="#9CA3AF" stroke-width="1.5" marker-end="url(#arrowBlue)" opacity="0.4"/>
<line x1="165" y1="190" x2="225" y2="212" stroke="#9CA3AF" stroke-width="1.5" marker-end="url(#arrowBlue)" opacity="0.4"/>
<!-- ============================================ -->
<!-- Monorepo B (right): a rounded rect with 2 internal projects -->
<!-- ============================================ -->
<rect x="640" y="70" width="260" height="200" rx="16" ry="16"
stroke="#9CA3AF" stroke-width="2" fill="none"/>
<text x="770" y="100" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="14" font-weight="600" fill="#9CA3AF">Monorepo B</text>
<!-- App 2 (blue) -->
<circle cx="710" cy="170" r="38" fill="#476088"/>
<text x="710" y="166" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="600" fill="white">App 2</text>
<text x="710" y="183" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="11" fill="#CBD5E1">backend</text>
<!-- Lib C (green) -->
<circle cx="840" cy="185" r="32" fill="#70AF40"/>
<text x="840" y="181" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="600" fill="white">Lib C</text>
<text x="840" y="197" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="11" fill="#E8F5E9">auth</text>
<!-- Internal arrow within Monorepo B -->
<line x1="745" y1="175" x2="808" y2="182" stroke="#9CA3AF" stroke-width="1.5" marker-end="url(#arrowBlue)" opacity="0.4"/>
<!-- ============================================ -->
<!-- Standalone repos -->
<!-- ============================================ -->
<!-- Lib D (green, standalone, CENTER - pushed down to middle row) -->
<circle cx="490" cy="340" r="38" fill="#70AF40"/>
<text x="490" y="336" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="600" fill="white">Lib D</text>
<text x="490" y="352" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="11" fill="#E8F5E9">shared</text>
<text x="490" y="390" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="11" font-weight="500" fill="#9CA3AF">standalone repo</text>
<!-- App 3 (blue, standalone, bottom-left) -->
<circle cx="200" cy="500" r="42" fill="#476088"/>
<text x="200" y="496" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="600" fill="white">App 3</text>
<text x="200" y="513" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="11" fill="#CBD5E1">mobile</text>
<text x="200" y="554" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="11" font-weight="500" fill="#9CA3AF">standalone repo</text>
<!-- Lib E (green, standalone, bottom-center) -->
<circle cx="490" cy="520" r="32" fill="#70AF40"/>
<text x="490" y="516" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="600" fill="white">Lib E</text>
<text x="490" y="532" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="11" fill="#E8F5E9">design</text>
<text x="490" y="564" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="11" font-weight="500" fill="#9CA3AF">standalone repo</text>
<!-- App 4 (blue, standalone, bottom-right) -->
<circle cx="770" cy="500" r="42" fill="#476088"/>
<text x="770" y="496" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="600" fill="white">App 4</text>
<text x="770" y="513" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="11" fill="#CBD5E1">API</text>
<text x="770" y="554" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="11" font-weight="500" fill="#9CA3AF">standalone repo</text>
<!-- ============================================ -->
<!-- Cross-repo dependency arrows -->
<!-- ============================================ -->
<!-- App 2 → Lib D (shared): curve down-left -->
<path d="M 675 185 C 620 240, 560 280, 525 325" stroke="#476088" stroke-width="2.5" fill="none" marker-end="url(#arrowBlue)"/>
<!-- Lib A → Lib D: gentle arc down -->
<path d="M 300 155 C 370 200, 420 260, 458 322" stroke="#70AF40" stroke-width="2" fill="none" marker-end="url(#arrowGreen)"/>
<!-- App 3 → Lib B (in Monorepo A): straight up -->
<path d="M 210 458 C 220 380, 230 320, 242 252" stroke="#476088" stroke-width="2.5" fill="none" marker-end="url(#arrowBlue)"/>
<!-- App 3 → Lib E (design): horizontal -->
<path d="M 242 500 C 320 490, 400 500, 458 515" stroke="#476088" stroke-width="2.5" fill="none" marker-end="url(#arrowBlue)"/>
<!-- App 4 → Lib C (in Monorepo B): straight up -->
<path d="M 790 458 C 805 380, 820 310, 835 217" stroke="#476088" stroke-width="2.5" fill="none" marker-end="url(#arrowBlue)"/>
<!-- App 4 → Lib D (shared): arc up-left -->
<path d="M 730 490 C 650 460, 570 410, 525 358" stroke="#476088" stroke-width="2.5" fill="none" marker-end="url(#arrowBlue)"/>
<!-- App 4 → Lib E (design): horizontal left -->
<path d="M 728 505 C 660 510, 580 515, 522 518" stroke="#476088" stroke-width="2" fill="none" marker-end="url(#arrowBlue)"/>
<!-- Lib D → Lib C (cross-repo lib dependency): arc up-right -->
<path d="M 525 330 C 620 300, 740 260, 812 200" stroke="#70AF40" stroke-width="2" fill="none" marker-end="url(#arrowGreen)"/>
</svg>

After

Width:  |  Height:  |  Size: 8.1 KiB

@@ -2,70 +2,119 @@
import { Icon } from '@astrojs/starlight/components';
import { getCollection } from 'astro:content';
const { pathname } = Astro.url;
const cleanedPath = pathname.split('?')[0];
const allDocs = await getCollection('docs');
const pathSegments = cleanedPath.split('/').filter(Boolean);
type Crumb = {
id: string;
name: string;
href: string;
label: string;
href?: string;
current: boolean;
};
function slugify(label: string): string {
return label
.replace(/\.NET/g, 'dotnet')
.toLowerCase()
.replace(/[^a-z0-9_]+/g, '-')
.replace(/^-+|-+$/g, '');
}
function findDocByPath (path: string) {
path = path.replace(/^docs\//, '');
return allDocs.find(d => d.id === `${path}`)
?? allDocs.find(d => d.id === `${path}/index`);
// --- Primary: Sidebar-based breadcrumbs ---
const sidebar = Astro.locals.starlightRoute.sidebar;
function findBreadcrumbPath(
entries: typeof sidebar,
path: Crumb[] = [],
slugSegments: string[] = []
): Crumb[] | null {
for (const entry of entries) {
if (entry.type === 'link' && entry.isCurrent) {
return [...path, { label: entry.label, href: entry.href, current: true }];
}
if (entry.type === 'group') {
const currentSlugs = [...slugSegments, slugify(entry.label)];
const groupHref = `/docs/${currentSlugs.join('/')}`;
const result = findBreadcrumbPath(
entry.entries,
[
...path,
{ label: entry.label, href: groupHref, current: false },
],
currentSlugs
);
if (result) return result;
}
}
return null;
}
function createNameFromSegment(segment: string): string {
let crumbs: Crumb[] = findBreadcrumbPath(sidebar) ?? [];
// --- Fallback: URL-path-based breadcrumbs ---
if (crumbs.length === 0) {
const { pathname } = Astro.url;
const cleanedPath = pathname.split('?')[0];
const allDocs = await getCollection('docs');
const pathSegments = cleanedPath.split('/').filter(Boolean);
function findDocByPath(path: string) {
path = path.replace(/^docs\//, '');
return (
allDocs.find((d) => d.id === `${path}`) ??
allDocs.find((d) => d.id === `${path}/index`)
);
}
function createNameFromSegment(segment: string): string {
segment = segment.split('#')[0];
return segment
.split('-')
.map(s => s.charAt(0).toUpperCase() + s.slice(1))
.join(' ');
.split('-')
.map((s) => s.charAt(0).toUpperCase() + s.slice(1))
.join(' ');
}
crumbs = pathSegments
.map((segment, index) => {
const docPath = pathSegments.slice(0, index + 1).join('/');
const doc = findDocByPath(docPath);
const label =
doc?.data?.sidebar?.label ||
doc?.data?.title ||
createNameFromSegment(segment);
// If `base` is set in config, don't include it in breadcrumbs
if (index === 0 && import.meta.env.BASE_URL) return null;
return {
label,
href: `/${docPath}`,
current: index === pathSegments.length - 1,
};
})
.filter(Boolean) as Crumb[];
}
const crumbs: Crumb[] = pathSegments.map((segment, index) => {
const docPath = pathSegments.slice(0, index + 1).join('/');
const doc = findDocByPath(docPath);
const name = doc?.data?.sidebar?.label || doc?.data?.title || createNameFromSegment(segment);
// If `base` is set in config, don't include it in breadcrumbs
if (index === 0 && import.meta.env.BASE_URL) return null;
return {
id: segment,
name,
href: `/${docPath}`,
current: index === pathSegments.length - 1,
};
}).filter(Boolean);
---
<nav class="not-content flex mb-4" aria-label="Breadcrumb">
<ol role="list" class="flex m-0 p-0 flex-wrap items-center space-x-2 text-sm">
{crumbs.map((crumb, index) => (
<li class="flex items-center">
{index > 0 && (
<Icon name="right-caret" class="w-5 h-5 ml-2 mr-2"/>
)}
<a
href={crumb.href}
class={`no-underline text-sm${
crumb.current
? ' text-slate-900 dark:text-slate-100 font-semibold'
: ' text-slate-500 dark:text-slate-400 font-medium hover:text-slate-700 dark:hover:text-slate-200'
} transition-colors`}
aria-current={crumb.current ? 'page' : undefined}
>
{crumb.name}
</a>
</li>
))}
{
crumbs.map((crumb, index) => (
<li class="flex items-center">
{index > 0 && <Icon name="right-caret" class="w-5 h-5 ml-2 mr-2" />}
{crumb.href ? (
<a
href={crumb.href}
class={`no-underline text-sm${
crumb.current
? ' text-slate-900 dark:text-slate-100 font-semibold'
: ' text-slate-500 dark:text-slate-400 font-medium hover:text-slate-700 dark:hover:text-slate-200'
} transition-colors`}
aria-current={crumb.current ? 'page' : undefined}
>
{crumb.label}
</a>
) : (
<span class="text-sm text-slate-500 dark:text-slate-400 font-medium">
{crumb.label}
</span>
)}
</li>
))
}
</ol>
</nav>
+16 -8
View File
@@ -509,7 +509,7 @@ const currentVersion = versions.find((v) => v.current);
</div>
<script>
import { sendCustomEvent } from '@nx/nx-dev-feature-analytics';
import { sendCustomEventViaGtm } from '@nx/nx-dev-feature-analytics';
function setupAnalyticsTracking() {
const docsHomeLink = document.getElementById('header-docs-home-link');
@@ -521,7 +521,7 @@ const currentVersion = versions.find((v) => v.current);
const tryNxCloudBtn = document.getElementById('header-try-nx-cloud-btn');
docsHomeLink?.addEventListener('click', () => {
sendCustomEvent(
sendCustomEventViaGtm(
'documentation-click',
'header-navigation',
'documentation-header'
@@ -529,7 +529,7 @@ const currentVersion = versions.find((v) => v.current);
});
aiLink?.addEventListener('click', () => {
sendCustomEvent(
sendCustomEventViaGtm(
'ai-click',
'header-navigation',
'documentation-header'
@@ -537,7 +537,7 @@ const currentVersion = versions.find((v) => v.current);
});
nxCloudLink?.addEventListener('click', () => {
sendCustomEvent(
sendCustomEventViaGtm(
'nx-cloud-click',
'header-navigation',
'documentation-header'
@@ -545,7 +545,7 @@ const currentVersion = versions.find((v) => v.current);
});
pricingLink?.addEventListener('click', () => {
sendCustomEvent(
sendCustomEventViaGtm(
'pricing-click',
'header-navigation',
'documentation-header'
@@ -553,7 +553,7 @@ const currentVersion = versions.find((v) => v.current);
});
enterpriseLink?.addEventListener('click', () => {
sendCustomEvent(
sendCustomEventViaGtm(
'enterprise-click',
'header-navigation',
'documentation-header'
@@ -561,11 +561,19 @@ const currentVersion = versions.find((v) => v.current);
});
contactBtn?.addEventListener('click', () => {
sendCustomEvent('contact-click', 'header-cta', 'documentation-header');
sendCustomEventViaGtm(
'contact-click',
'header-cta',
'documentation-header'
);
});
tryNxCloudBtn?.addEventListener('click', () => {
sendCustomEvent('login-click', 'header-cta', 'documentation-header');
sendCustomEventViaGtm(
'login-click',
'header-cta',
'documentation-header'
);
});
}
@@ -38,7 +38,7 @@ const bannerId = bannerConfig ? `${bannerConfig.title}-${bannerConfig.activeUnti
<GitHubStarWidget starsCount={githubStarsCount} client:load />
<div class="flex flex-col mx-2 gap-2">
<a
href="https://nx.dev/contact"
href={`${import.meta.env.SITE || 'https://nx.dev'}/contact`}
class="w-full inline-flex items-center justify-center px-4 py-2 text-sm font-medium rounded-md transition no-underline border border-slate-300 dark:border-slate-700 bg-white dark:bg-slate-800 text-slate-700 dark:text-slate-200 hover:bg-slate-50 dark:hover:bg-slate-700 shadow-sm"
title="Contact Us"
>
@@ -0,0 +1,108 @@
---
import { getCollection } from 'astro:content';
import Cards from './Cards.astro';
import LinkCard from './LinkCard.astro';
export interface Props {
group: string;
}
const { group } = Astro.props;
const groupSegments = group.split('/');
// Use the Starlight resolved sidebar from Astro locals
const sidebar = Astro.locals.starlightRoute.sidebar;
type SidebarEntry = (typeof sidebar)[number];
function findGroup(
entries: SidebarEntry[],
segments: string[],
depth: number = 0
): SidebarEntry | null {
for (const entry of entries) {
if (entry.type === 'group' && entry.label === segments[depth]) {
if (depth === segments.length - 1) {
return entry;
}
return findGroup(entry.entries, segments, depth + 1);
}
}
return null;
}
interface LinkItem {
label: string;
href: string;
}
function slugify(label: string): string {
return label
.replace(/\.NET/g, 'dotnet')
.toLowerCase()
.replace(/[^a-z0-9_]+/g, '-')
.replace(/^-+|-+$/g, '');
}
// Build base URL path from the group prop segments
const baseSlug = groupSegments.map((s) => slugify(s)).join('/');
function collectTopLevelItems(entries: SidebarEntry[]): LinkItem[] {
const items: LinkItem[] = [];
for (const entry of entries) {
if (entry.type === 'link') {
items.push({ label: entry.label, href: entry.href });
}
if (entry.type === 'group') {
const groupSlug = slugify(entry.label);
items.push({
label: entry.label,
href: `/docs/${baseSlug}/${groupSlug}`,
});
}
}
return items;
}
const matchedGroup = findGroup(sidebar, groupSegments);
const linkItems =
matchedGroup && matchedGroup.type === 'group'
? collectTopLevelItems(matchedGroup.entries)
: [];
// Look up each page in the docs collection for descriptions
const allDocs = await getCollection('docs');
const processedPages = linkItems.map((item) => {
const docPath = item.href.replace(/^\/docs\//, '');
const doc = allDocs.find(
(d) =>
d.id === docPath ||
d.id === `${docPath}.mdoc` ||
d.id === `${docPath}/index` ||
d.id === `${docPath}/index.mdoc`
);
return {
title: item.label,
description: doc?.data?.description || '',
href: item.href,
};
});
---
{
processedPages.length > 0 ? (
<Cards>
{processedPages.map((page) => (
<LinkCard
title={page.title}
description={page.description}
href={page.href}
type="documentation"
/>
))}
</Cards>
) : (
<p>No pages found in this section.</p>
)
}
@@ -548,5 +548,10 @@
"name": "@berenddeboer/nx-biome",
"description": "A self-inferring Nx plugin for using biome to format and lint projects. Supports --batch",
"url": "https://github.com/berenddeboer/nx-plugins/tree/main/packages/nx-biome"
},
{
"name": "@berenddeboer/nx-knip",
"description": "A self-inferring Nx plugin for using knip to find and fix unused dependencies, exports and files",
"url": "https://github.com/berenddeboer/nx-plugins/tree/main/packages/nx-knip"
}
]
@@ -24,7 +24,7 @@ By default, the computation hash for something like `nx test remixapp` includes:
After Nx computes the hash for a task, it then checks if it ran this exact computation before. First, it checks locally, and then if it is missing, and if a remote cache is configured, it checks remotely. If a matching computation is found, Nx retrieves and replays it. This includes restoring files.
Nx places the right files in the right folders and prints the terminal output. From the user's point of view, the command ran the same, just a lot faster.
Nx places the right files in the right folders and prints the terminal output. From the user's point of view, the command ran the same, only a lot faster.
![cache](../../../assets/concepts/caching/cache.svg)
@@ -32,7 +32,7 @@ If Nx doesn't find a corresponding computation hash, Nx runs the task, and after
## Optimizations
Although conceptually this is fairly straightforward, Nx optimizes the experience for you. For instance, Nx:
Nx optimizes the caching experience in several ways. For instance, Nx:
- Captures stdout and stderr to make sure the replayed output looks the same, including on Windows.
- Minimizes the IO by remembering what files are replayed where.
@@ -46,7 +46,7 @@ As your workspace grows, the task graph looks more like this:
All of these optimizations are crucial for making Nx usable for any non-trivial workspace. Only the minimum amount of
work happens. The rest is either left as is or restored from the cache.
## Fine-tuning Nx's Cache
## Fine-tuning the Nx cache
Each cacheable task defines a set of inputs and outputs. Inputs are factors Nx considers when calculating the computation hash.
Outputs are files that will be cached and restored when the computation hash matches.
@@ -6,9 +6,7 @@ sidebar:
filter: 'type:Concepts'
---
Nx is a VSCode of build tools, with a powerful core, driven by metadata, and extensible through [plugins](/docs/concepts/nx-plugins). Nx works with a
few concepts to drive your monorepo efficiently, and effectively. This guide covers the mental model around how Nx works
with project graphs, task graphs, affected commands, computation hashing and caching.
Nx is a VSCode of build tools, with a powerful core, driven by metadata, and extensible through [plugins](/docs/concepts/nx-plugins). Nx works with a few core concepts to drive your monorepo efficiently: project graphs, task graphs, affected commands, computation hashing, and caching.
## The project graph
@@ -267,7 +265,7 @@ With this, running the same test command creates the following task graph:
This often makes more sense for builds, where to build `app1`, you want to build `lib` first. You can also define
similar
relationships between targets of the same project, including a test target that depends on the build.
relationships between targets of the same project, including a test target that depends on the build. Learn more about configuring task pipelines in [Task Pipeline Configuration](/docs/concepts/task-pipeline-configuration).
A task graph can contain different targets, and those can run in parallel. For instance, as Nx is building `app2`, it
can be testing `app1` at the same time.
@@ -287,7 +285,7 @@ and `lib:test`.
When you run `nx run-many -t test`, you are telling Nx to do this for all the projects.
As your workspace grows, retesting all projects becomes too slow. To address this Nx implements code change analysis to
As your workspace grows, retesting all projects becomes too slow. To address this Nx implements code change analysis via the [`affected` command](/docs/features/ci-features/affected) to
get the min set of projects that need to be retested. How does it work?
When you run `nx affected -t test`, Nx looks at the files you changed in your PR, it will look at the nature of
@@ -304,104 +302,19 @@ that `app2` cannot be affected by it, so it only retests `app1`.
## Computation hashing and caching
Nx runs the tasks in the task graph in the right order. Before running the task, Nx computes its computation hash. As
long as the computation hash is the same, the output of running the task is the same.
How does Nx do it?
By default, the computation hash for say `nx test app1` includes:
- All the source files of `app1` and `lib`
- Relevant global configuration
- Versions of external dependencies
- [Runtime values provisioned by the user](/docs/reference/inputs#runtime-inputs)
- CLI Command flags
Before running a task, Nx computes a hash based on source files, configuration, dependencies, and other inputs. If the hash matches a previous run, the cached result is replayed — including terminal output and file artifacts. If not, Nx runs the task and stores the result for next time.
![computation-hashing](../../../assets/concepts/mental-model/computation-hashing.svg)
This behavior is customizable. For instance, lint checks may only depend on the source code of the project and global
configs. Builds can depend on the `.d.ts` files of the compiled libs instead of their source.
After Nx computes the hash for a task, it then checks if it ran this exact computation before. First, it checks locally,
and then if it is missing, and if a remote cache is configured, it checks remotely.
If Nx finds the computation, Nx retrieves it and replays it. Nx places the right files in the right folders and prints
the terminal output. So from the user's point of view, the command ran the same, just a lot faster.
Nx checks the local cache first, then the [remote cache](/docs/features/ci-features/remote-cache) if configured. From the user's point of view, the command ran the same, only a lot faster.
![cache](../../../assets/concepts/mental-model/cache.svg)
If Nx doesn't find this computation, Nx runs the task, and after it completes, it takes the outputs and the terminal
output and stores it locally (and if configured remotely). All of this happens transparently, so you don't have to worry
about it.
Although conceptually this is fairly straightforward, Nx optimizes this to make this experience good for you. For
instance, Nx:
- Captures stdout and stderr to make sure the replayed output looks the same, including on Windows.
- Minimizes the IO by remembering what files are replayed where.
- Only shows relevant output when processing a large task graph.
- Provides affordances for troubleshooting cache misses. And many other optimizations.
As your workspace grows, the task graph looks more like this:
{% graph height="200px" type="task"%}
```json
{
"projects": [
{
"name": "lib",
"type": "lib",
"data": {
"tags": [],
"targets": {
"test": {}
}
}
}
],
"taskIds": ["lib:test"],
"taskGraph": {
"roots": ["lib:test"],
"tasks": {
"lib:test": {
"id": "lib:test",
"target": {
"project": "lib",
"target": "test"
},
"projectRoot": "libs/lib",
"overrides": {}
}
},
"dependencies": {}
}
}
```
{% /graph %}
All of these optimizations are crucial for making Nx usable for any non-trivial workspace. Only the minimum amount of
work happens. The rest is either left as is or restored from the cache.
See [How Caching Works](/docs/concepts/how-caching-works) for the complete list of hash inputs, cache configuration options, and optimization details.
## Distributed task execution
Nx supports running commands across multiple machines. You can either set it up by hand or use Nx Cloud. [Read the comparison of the two approaches.](https://nx.dev/blog/distributing-ci-binning-and-distributed-task-execution)
When using the distributed task execution, Nx is able to run any task graph on many agents instead of locally.
For instance, `nx affected --build` won't run the build locally (which can take hours for large workspaces). Instead,
it will send the Task Graph to Nx Cloud. Nx Cloud Agents will then pick up the tasks they can run and execute them.
Note that this happens transparently. If an agent builds `app1`, it will fetch the outputs for `lib` if it doesn't have
them
already.
As agents complete tasks, the main job where you invoked `nx affected --build` will start receiving created files and
terminal outputs.
After `nx affected --build` completes, the machine will have the build files and all the terminal outputs as if it ran
it locally.
For large workspaces, even with caching, running all tasks on a single machine can be slow. [Nx Agents](/docs/features/ci-features/distribute-task-execution) can distribute the task graph across multiple machines, running tasks in parallel while using [remote caching](/docs/features/ci-features/remote-cache) to share artifacts between agents. From your CI's perspective, the results appear as if everything ran on a single machine.
![Distribution](../../../assets/concepts/mental-model/dte.svg)
@@ -410,5 +323,5 @@ it locally.
- Nx is able to analyze your source code to create a Project Graph.
- Nx can use the project graph and information about projects' targets to create a Task Graph.
- Nx is able to perform code-change analysis to create the smallest task graph for your PR.
- Nx supports computation caching to never execute the same computation twice. This computation cache is pluggable and
- Nx supports [computation caching](/docs/features/cache-task-results) to never execute the same computation twice. This computation cache is pluggable and
can be distributed.
@@ -49,7 +49,7 @@ To see information about the running Nx Daemon (such as its background process I
## Customizing the socket location
The Nx Daemon uses a unix socket to communicate between the daemon and the Nx processes. By default this socket gets placed in a temp directory. If you are using Nx in a docker-compose environment, however, you may want to run the daemon manually
and control its location to enable sharing the daemon among your docker containers. To do so, simply set the NX_DAEMON_SOCKET_DIR environment variable to a shared directory.
and control its location to enable sharing the daemon among your docker containers. To do so, set the `NX_DAEMON_SOCKET_DIR` environment variable to a shared directory.
## Daemon Behavior in Containers
@@ -13,7 +13,7 @@ For example, plugins can accomplish the following:
- [Configure Nx cache settings](/docs/concepts/inferred-tasks) for a tool. The [`@nx/webpack`](/docs/technologies/build-tools/webpack/introduction) plugin can automatically configure the [inputs](/docs/guides/tasks--caching/configure-inputs) and [outputs](/docs/guides/tasks--caching/configure-outputs) for a `build` task based on the settings in the `webpack.config.js` file it uses.
- [Update tooling configuration](/docs/features/automate-updating-dependencies) when upgrading the tool version. When Storybook 7 introduced a [new format](https://storybook.js.org/blog/storybook-csf3-is-here) for their configuration files, anyone using the [`@nx/storybook`](/docs/technologies/test-tools/storybook/introduction) plugin could automatically apply those changes to their repository when upgrading.
- [Set up a tool](/docs/features/generate-code) for the first time. With the [`@nx/playwright`](/docs/technologies/test-tools/playwright/introduction) plugin installed, you can use the `@nx/playwright:configuration` code generator to set up Playwright tests in an existing project.
- [Run a tool in an advanced way](/docs/concepts/executors-and-configurations). The [`@nx/js`](/docs/technologies/typescript/introduction) plugin's [`@nx/js:tsc` executor](/docs/technologies/typescript/executors#tsc) combines Nx's understanding of your repository with Typescript's native batch mode feature to make your builds [even more performant](/docs/technologies/typescript/guides/enable-tsc-batch-mode).
- [Run a tool in an advanced way](/docs/concepts/executors-and-configurations). The [`@nx/js`](/docs/technologies/typescript/introduction) plugin's [`@nx/js:tsc` executor](/docs/technologies/typescript/executors#tsc) combines the Nx understanding of your repository with Typescript's native batch mode feature to make your builds [even more performant](/docs/technologies/typescript/guides/enable-tsc-batch-mode).
## Plugin Features
@@ -0,0 +1,48 @@
---
title: Synthetic Monorepos
description: Learn how synthetic monorepos connect separate repositories into a unified dependency graph, giving you monorepo intelligence without moving code.
---
Most organizations don't have a single giant monorepo. They have a handful of monorepos per team or domain, plus dozens of standalone repos. Consolidating everything into one repository is not just a technical challenge. The organizational side (bringing teams along, changing workflows, ensuring adoption) is often harder than the code migration itself.
Synthetic monorepos let you get monorepo benefits without that consolidation.
## What is a synthetic monorepo?
A synthetic monorepo connects separate repositories into a unified dependency graph without moving any code. Which repo depends on which, what a change affects downstream, how projects relate across teams: all of that becomes visible automatically.
![A synthetic monorepo connecting multiple monorepos and standalone repos into a unified dependency graph](../../../assets/concepts/synthetic-monorepo.svg)
Unlike a traditional monorepo where all code lives in one repository, a synthetic monorepo leaves each repository where it is. Instead, it builds a cross-repo graph that tooling can reason about, just as if the code were in one place.
## What synthetic monorepos enable
A synthetic monorepo addresses several downsides of a polyrepo setup:
**Visibility** — An automatic cross-repo dependency graph shows which repo depends on which and what a change affects downstream. Always up to date, discovered from actual code — not a manually maintained spreadsheet or catalog. Nx implements this through the [Workspace Graph](/docs/enterprise/polygraph).
**Coordination** — Cross-repo changes no longer require manually sequencing PRs, managing compatibility, and coordinating release order. Tooling on top of the graph enables impact analysis, coordinated changes, and conformance checking across repo boundaries.
**Governance** — Organizational standards apply across every connected repo through [conformance rules](/docs/enterprise/conformance). Scheduled [custom workflows](/docs/enterprise/custom-workflows) check repos continuously — even ones nobody has touched in months. Detection and enforcement happen automatically, not through tickets and follow-ups.
**CI intelligence** — [Affected detection](/docs/concepts/mental-model#affected-commands), [remote caching](/docs/concepts/how-caching-works), and [distributed task execution](/docs/concepts/ci-concepts/parallelization-distribution) work across the full graph, not just within a single repo.
**AI agents** — AI coding agents are [dramatically less effective in polyrepos](https://youtu.be/alIto5fqrfk) — they can only see one repo at a time, so cross-repo features require you to manually shuttle context between sessions. A synthetic monorepo gives agents cross-repo visibility, enabling coordinated changes, parallel execution, and automatic PR creation across boundaries. [Self-healing CI](/docs/features/ci-features/self-healing-ci) catches failures automatically.
## When to use a synthetic monorepo vs. a real monorepo
A real monorepo is the best option when you can consolidate. It gives you atomic commits, a single toolchain, and the simplest mental model.
A synthetic monorepo is the better starting point when:
- **Consolidation isn't feasible yet:** team autonomy concerns, divergent CI setups, or hundreds of repos make migration impractical.
- **You need cross-repo visibility now:** you can't wait months for a migration to see how projects relate across teams.
- **Teams need to stay autonomous:** each team keeps their repo, workflow, and release cadence while still participating in a unified graph.
The two aren't mutually exclusive. Start synthetic for org-wide visibility, then consolidate tightly coupled teams into real monorepos where it makes sense.
## Synthetic monorepos with Nx Polygraph
Nx implements synthetic monorepos through [Nx Polygraph](/docs/enterprise/polygraph). Polygraph connects existing repositories into a unified, intelligent graph that powers the visibility, coordination, and CI features described above. It works with any repo, even those that don't use Nx, and requires zero changes to target repos.
Learn more about [getting started with Nx Polygraph](/docs/enterprise/polygraph).
@@ -65,7 +65,7 @@ This becomes even more evident when you run tasks in parallel. You cannot just n
![task-graph-execution](../../../assets/concepts/mental-model/task-graph-execution.svg)
Nx allows you to define task dependencies in the form of "rules", which are then followed when running tasks. There's a [detailed recipe](/docs/guides/tasks--caching/defining-task-pipeline) but here's the high-level overview:
Define task dependencies in the form of "rules", which are then followed when running tasks. There's a [detailed recipe](/docs/guides/tasks--caching/defining-task-pipeline) but here's the high-level overview:
```jsonc title="nx.json"
{
@@ -55,7 +55,7 @@ The configuration for package manager workspaces varies based on which package m
Defining the `workspaces` property in the root `package.json` file lets npm know to look for other `package.json` files in the specified folders. With this configuration in place, all the dependencies for the individual projects will be installed in the root `node_modules` folder when `npm install` is run in the root folder. Also, the projects themselves will be linked in the root `node_modules` folder to be accessed as if they were npm packages.
If you want to reference a local library project with its own `build` task, you should include the library in the `devDependencies` of the application's `package.json` with `*` specified as the library's version. `*` tells npm to use whatever version of the project is available.
If you want to reference a local library project with its own `build` task, you should include the library in the `devDependencies` of the application/library's `package.json` with `*` specified as the library's version. `*` tells npm to use whatever version of the project is available.
```json title="/apps/my-app/package.json"
{
@@ -76,7 +76,7 @@ If you want to reference a local library project with its own `build` task, you
Defining the `workspaces` property in the root `package.json` file lets yarn know to look for other `package.json` files in the specified folders. With this configuration in place, all the dependencies for the individual projects will be installed in the root `node_modules` folder when `yarn` is run in the root folder. Also, the projects themselves will be linked in the root `node_modules` folder to be accessed as if they were npm packages.
If you want to reference a local library project with its own `build` task, you should include the library in the `devDependencies` of the application's `package.json` with `workspace:*` specified as the library's version. [`workspace:*` tells yarn that the project is in the same repository](https://yarnpkg.com/features/workspaces) and not an npm package. You want to specify local projects as `devDependencies` instead of `dependencies` so that the library is not included twice in the production bundle of the application.
If you want to reference a local library project with its own `build` task, you should include the library in the `devDependencies` of the application/library's `package.json` with `workspace:*` specified as the library's version. [`workspace:*` tells yarn that the project is in the same repository](https://yarnpkg.com/features/workspaces) and not an npm package. You want to specify local projects as `devDependencies` instead of `dependencies` so that the library is not included twice in the production bundle of the application.
```json title="/apps/my-app/package.json"
{
@@ -97,7 +97,7 @@ If you want to reference a local library project with its own `build` task, you
Defining the `workspaces` property in the root `package.json` file lets bun know to look for other `package.json` files in the specified folders. With this configuration in place, all the dependencies for the individual projects will be installed in the root `node_modules` folder when `bun install` is run in the root folder. Also, the projects themselves will be linked in the root `node_modules` folder to be accessed as if they were npm packages.
If you want to reference a local library project with its own `build` task, you should include the library in the `devDependencies` of the application's `package.json` with `workspace:*` specified as the library's version. [`workspace:*` tells bun that the project is in the same repository](https://bun.sh/docs/install/workspaces) and not an npm package. You want to specify local projects as `devDependencies` instead of `dependencies` so that the library is not included twice in the production bundle of the application.
If you want to reference a local library project with its own `build` task, you should include the library in the `devDependencies` of the application/library's `package.json` with `workspace:*` specified as the library's version. [`workspace:*` tells bun that the project is in the same repository](https://bun.sh/docs/install/workspaces) and not an npm package. You want to specify local projects as `devDependencies` instead of `dependencies` so that the library is not included twice in the production bundle of the application.
```json title="/apps/my-app/package.json"
{
@@ -187,7 +187,7 @@ Each project's `tsconfig.json` file should extend the `tsconfig.base.json` file
}
```
Each project's `tsconfig.lib.json` file extends the project's `tsconfig.json` file and adds `references` to the `tsconfig.lib.json` files of project dependencies.
Each project's `tsconfig.lib.json` file extends the `tsconfig.base.json` file and adds `references` to the `tsconfig.lib.json` files of project dependencies.
```jsonc title="packages/cart/tsconfig.lib.json"
{
@@ -4,7 +4,7 @@ description: Create and publish custom Nx Conformance rules to your Nx Cloud org
filter: 'type:Guides'
---
[Nx Cloud Enterprise](https://nx.dev/enterprise) allows you to publish your organization's [Nx Conformance](/docs/enterprise/conformance) rules to your Nx Cloud Organization, and consume them in any of your other Nx Workspaces without having to deal with the complexity and friction of dealing with a private NPM registry or similar. Authentication is handled automatically through your Nx Cloud connection and rules are downloaded and applied based on your preferences configured in the Nx Cloud UI.
[Nx Cloud Enterprise](https://nx.dev/enterprise) lets you publish custom [Nx Conformance](/docs/enterprise/conformance) rules to your Nx Cloud Organization and consume them across workspaces — no private NPM registry needed. See [Configure Conformance Rules in Nx Cloud](/docs/enterprise/configure-conformance-rules-in-nx-cloud) for how to manage published rules in the UI.
Let's create a custom rule which we can then publish to Nx Cloud. We will first create a new library project to contain our rule (and any others we might create in the future):
@@ -128,6 +128,184 @@ Nx uses the paths from `tsconfig.base.json` when running plugins locally, but us
![vscode-schematics-debug](../../../assets/nx-console/vscode-schematics-debug.png)
## Generator Schema Properties
Beyond the standard [JSON Schema](https://json-schema.org/) properties like `type`, `description`, `enum`, and `default`, Nx recognizes several custom properties in your `schema.json` that control CLI prompting behavior and how [Nx Console](/docs/getting-started/editor-setup) renders the generator form.
### `$default`
Provides a dynamic default value from a runtime source. Used to map positional CLI arguments and other context to schema properties.
```json
// schema.json
{
"properties": {
"name": {
"type": "string",
"$default": {
"$source": "argv",
"index": 0
}
}
}
}
```
| Source | Description |
| ----------------------------------- | ------------------------------------------------------------------------------------------- |
| `{ "$source": "argv", "index": 0 }` | Uses the positional CLI argument at the given index |
| `{ "$source": "projectName" }` | Uses the current project name. Also triggers project autocomplete in the CLI and Nx Console |
| `{ "$source": "workingDirectory" }` | Uses the current working directory relative to the workspace root |
| `{ "$source": "unparsed" }` | Collects any extra arguments not matched by other schema properties |
### `x-prompt`
Defines an interactive prompt shown when the option is not provided on the command line. Can be a simple string or a structured object for more control.
```json
// schema.json
{
"properties": {
"style": {
"type": "string",
"description": "The file extension to be used for style files.",
"x-prompt": {
"message": "Which stylesheet format would you like to use?",
"type": "list",
"items": [
{ "value": "css", "label": "CSS" },
{ "value": "scss", "label": "SASS (.scss)" },
{ "value": "less", "label": "LESS" }
]
}
}
}
}
```
**Short form:** `"x-prompt": "What name would you like to use?"` — displays a simple text prompt.
**Long form object properties:**
| Property | Type | Description |
| ------------- | ------------------------------------------------ | ----------------------------------------------------- |
| `message` | `string` | The prompt text displayed to the user |
| `type` | `string` | Prompt type: `"input"`, `"list"`, or `"confirmation"` |
| `multiselect` | `boolean` | Allow selecting multiple items (for `"list"` type) |
| `items` | `(string \| { label: string, value: string })[]` | Choices for `"list"` type prompts |
In Nx Console, the `message` is shown as a tooltip on the field and `items` labels are shown as option descriptions.
### `x-priority`
Controls the visibility and ordering of an option in the Nx Console Generate form.
```json
// schema.json
{
"properties": {
"name": {
"type": "string",
"x-priority": "important"
},
"skipFormat": {
"type": "boolean",
"x-priority": "internal"
}
}
}
```
| Value | Effect |
| ------------- | ------------------------------------------------------------- |
| `"important"` | Field appears near the top of the form, after required fields |
| `"internal"` | Field is hidden from the form by default |
Options in the Nx Console form are sorted: **required** > **important** > **regular** > **deprecated** > **internal**.
### `x-deprecated`
Marks an option as deprecated. Deprecated options are sorted to the bottom of the form in Nx Console and display a warning.
```json
// schema.json
{
"properties": {
"oldOption": {
"type": "string",
"x-deprecated": "Use 'newOption' instead."
}
}
}
```
The value can be `true` (boolean) or a string with the deprecation reason/migration guidance.
### `x-dropdown`
Tells both the CLI and Nx Console to present a dropdown populated with workspace data.
```json
// schema.json
{
"properties": {
"projectName": {
"type": "string",
"x-dropdown": "projects"
}
}
}
```
Currently only `"projects"` is supported, which shows all projects in the workspace.
{% aside type="note" title="Automatic project autocomplete" %}
The CLI and Nx Console also automatically provide project autocomplete for any property named `project` or `projectName`, or that has `$default` set to `{ "$source": "projectName" }` — even without `x-dropdown`.
{% /aside %}
### `x-hint`
Displays a hint popover next to the field label in the Nx Console Generate form. Use this for brief contextual guidance that doesn't belong in the main `description`.
```json
// schema.json
{
"properties": {
"name": {
"type": "string",
"x-hint": "You can provide a nested path like my-dir/my-lib"
}
}
}
```
### `x-completion-type` and `x-completion-glob`
These properties are used by Nx Console's language server to provide autocomplete suggestions when editing configuration files like `project.json` or `nx.json`.
```json
// schema.json
{
"properties": {
"tsConfig": {
"type": "string",
"x-completion-type": "file",
"x-completion-glob": "tsconfig*.json"
}
}
}
```
| `x-completion-type` value | Description |
| ------------------------- | ------------------------------------------------------------------------- |
| `"file"` | Autocomplete with file paths (optionally filtered by `x-completion-glob`) |
| `"directory"` | Autocomplete with directory paths |
| `"projects"` | Autocomplete with workspace project names |
| `"targets"` | Autocomplete with available target names |
| `"targetsWithDeps"` | Autocomplete targets, including `^target` syntax for dependencies |
| `"tags"` | Autocomplete with project tags |
| `"projectTarget"` | Autocomplete with `project:target` format |
## Generator Utilities
The [`@nx/devkit` package](/docs/reference/devkit) provides many utility functions that can be used in generators to help with modifying files, reading and updating configuration files, and working with an Abstract Syntax Tree (AST).
@@ -11,12 +11,10 @@ src="https://youtu.be/NF1__N_snog"
title="Remote Caching with Nx Replay"
/%}
Repeatedly rebuilding and retesting the same code is costly — not just in terms of wasted resources, but also in terms of developer time. To solve this, Nx includes a sophisticated computation caching system that ensures **code is never rebuilt twice**, saving you both time and resources.
Nx [caches task results locally](/docs/features/cache-task-results) to avoid rebuilding the same code twice. Remote caching extends this by **sharing the cache across your team and CI**.
![Diagram showing Teika sharing his cache with CI, Kimiko and James](../../../../assets/features/distributed-caching.svg)
By default, Nx [caches task computations locally](/docs/features/cache-task-results), but the biggest benefit comes from **sharing this cache across your team and in CI**.
- **Zero config** and **secure** by default
- Drastically **speeds up task execution times** during local development, and more critically in CI
- **Saves money on CI/CD costs** by reducing the number of tasks that need to be executed (we observed 30-70% faster CI & half the cost)
@@ -16,7 +16,7 @@ Nx Cloud Self-Healing CI is an **AI-powered system that automatically detects, a
- **Improves Time to Green (TTG):** Automatically proposes fixes when tasks fail, significantly reducing the time to get your PR merge-ready. No more babysitting PRs.
- **Keeps You in the Flow:** Get notified about failed PRs and proposed fixes via PR/MR comments or directly in your editor with Nx Console (VS Code, Cursor, or WebStorm). Review, approve, and keep working while AI handles the rest.
- **Leverages Deep Context:** AI agents understand your workspace structure, project relationships, and build configurations through Nx's project graph and metadata.
- **Leverages Deep Context:** AI agents understand your workspace structure, project relationships, and build configurations through the Nx [project graph](/docs/features/explore-graph) and metadata.
- **Non-Invasive Integration:** Works with your existing CI provider without overhauling your current setup.
## Enable Self-Healing CI
@@ -26,8 +26,8 @@ npx nx configure-ai-agents
This sets up:
- **Agent configuration files**: `CLAUDE.md`, `AGENTS.md` with workspace-specific guidelines
- **Agent skills**: Specialized capabilities for monorepo workflows, including CI monitoring and self-healing integration
- **Nx MCP server**: Provides tools that combine local workspace metadata with CI context, enabling seamless local-to-CI workflows that unlock true agent autonomy
- **Agent skills**: Domain-specific knowledge for monorepo workflows — workspace exploration, code generation, task execution, CI monitoring, and package linking. Skills teach agents _how_ to work with Nx rather than dumping data into context.
- **Nx MCP server**: Provides connectivity to Nx Cloud CI pipelines, self-healing fixes, running processes, and Nx documentation — things agents can't easily reach on their own
## What This Enables
@@ -83,12 +83,10 @@ If your repository is using package manager workspaces, Nx will use those settin
### Inferred Tasks with Tooling Plugins
Nx provides [plugins](/docs/concepts/nx-plugins) for tools that run tasks, like Vite, TypeScript, Playwright or Jest. These plugins can automatically [infer the Nx-specific task configuration](/docs/concepts/inferred-tasks) based on the tooling configuration files that already exist.
Nx [plugins](/docs/concepts/nx-plugins) for tools like Vite, TypeScript, Playwright, and Jest automatically [infer task configuration](/docs/concepts/inferred-tasks) from your existing tooling config files — keeping them as the single source of truth.
In the example below, because the `/apps/cart/vite.config.ts` file exists, Nx knows that the `cart` project can run a `build` task using Vite. If you expand the `build` task, you can also see that Nx configured the output directory for the [cache](/docs/features/cache-task-results) to match the `build.outDir` provided in the Vite configuration file.
With inferred tasks, you can keep your tooling configuration file as the one source of truth for that tool's configuration, instead of adding an extra layer of configuration on top.
```ts
// /apps/cart/vite.config.ts
/// <reference types='vitest' />
@@ -7,7 +7,9 @@ sidebar:
filter: 'type:Features'
---
This guide shows how to configure your Nx workspace for AI coding assistants. The setup gives your agent workspace context and CI integration, making it smarter when working in an Nx monorepo and more autonomous when iterating on CI failures.
AI coding assistants often hallucinate outdated Nx commands and lack context about your workspace structure. Without workspace awareness, they suggest commands that don't exist or miss project relationships entirely.
The Nx AI integration gives assistants accurate, real-time information about your workspace, projects, and available commands, making them smarter when working in an Nx monorepo and more autonomous when iterating on CI failures.
## Configure Nx AI Integration
@@ -24,7 +26,7 @@ To automatically configure your Nx monorepo to work best with AI agents and assi
npx nx configure-ai-agents
```
This will prompt you for which AI agents/assistants to configure and set up the [Nx MCP server](/docs/features/enhance-ai), AI agent configuration files (`AGENTS.md`, `CLAUDE.md`, etc.), and agent skills. For Claude Code, skills are installed via a plugin; for other agents, they're copied into your workspace.
This will prompt you for which AI agents/assistants to configure and set up the [Nx MCP server](/docs/reference/nx-mcp), AI agent configuration files (`AGENTS.md`, `CLAUDE.md`, etc.), and agent skills (for workspace exploration, code generation, and task execution). For Claude Code, skills are installed via a plugin; for other agents, they're copied into your workspace.
Alternatively, you can install just the skills via:
@@ -43,7 +45,7 @@ The Nx AI integration provides your coding assistant with powerful capabilities:
- **Workspace Understanding** - Graph-aware exploration of project dependencies and relationships. AI gets structured data instead of grepping through files.
- **[Real-time Terminal Integration](https://nx.dev/blog/nx-terminal-integration-ai)** - AI can read your terminal output, running processes, and error messages without copy-pasting.
- **Reliable Code Generation** - AI invokes Nx generators for predictable scaffolding, then adapts the result to your workspace. Faster, standardized, fewer hallucinations.
- **Autonomous CI Workflows** - The CI monitor skill bridges your local agent with Nx Cloud. Push, monitor, get failures, fix, repeat until CI is green. Enables "Ralph Wiggum loop" patterns where you review the final PR, not every CI hiccup.
- **Autonomous CI Workflows** - The CI monitor skill bridges your local agent with Nx Cloud. Push, monitor, get failures, fix, repeat until CI is green. Enables autonomous CI workflows ("Ralph Wiggum loop")—you review the final PR, not every intermediate fix.
- **Cross-project Impact Analysis** - Understanding the implications of changes across your entire monorepo.
## Configure CI to Leverage AI Capabilities
@@ -6,7 +6,9 @@ sidebar:
filter: 'type:Features'
---
Nx Console editor extensions make your developer experience richer. The extensions:
Running CLI commands manually and discovering available tasks is tedious. You lose context switching between terminal and editor, and it's easy to forget which generators or tasks are available for each project.
Nx Console brings Nx directly into your editor. The extensions:
- [enhance AI integrations](/docs/features/enhance-ai) by providing workspace-level context and up-to-date docs
- show [inferred tasks](/docs/concepts/inferred-tasks) and help you invoke them via the Project Details View
@@ -30,11 +32,11 @@ If you are using [VSCode](https://code.visualstudio.com/) or a [JetBrains IDE](h
![Nx Console screenshot](../../../assets/nx-console/nx-console-screenshot.webp)
### Neovim
### Neovim (Community)
If you are using [Neovim](https://neovim.io/), you can install [Equilibris/nx.nvim](https://github.com/Equilibris/nx.nvim) with your favorite package manager.
This plugin is **NOT** built or maintained by the Nx team. They are maintained by independent community contributors.
**Community Plugin**: This plugin is maintained by independent community contributors, not the Nx team.
## Troubleshooting
@@ -6,7 +6,7 @@ sidebar:
pagefind: false
---
Start your journey with Nx. Whether you're creating a new project or adding Nx to an existing codebase, we've got you covered.
Create a new workspace or add Nx to an existing project.
Choose your path based on your current setup and requirements. Nx works with any technology stack and can be adopted incrementally.
@@ -1,12 +1,15 @@
---
title: Installation
description: Install Nx globally via npm, Homebrew, Chocolatey, or apt. Add Nx to existing repos with nx init and keep dependencies updated automatically.
description: Install Nx globally via npm, Homebrew, Chocolatey, or apt. Add Nx to existing repos with nx init.
sidebar:
order: 2
filter: 'type:Guides'
---
To install Nx on your machine, choose one of the following methods based on your operating system and package manager. You can also use `npx` to run Nx without installing it globally.
## Global Installation
Install Nx globally to run commands from anywhere. Choose a method based on your operating system and package manager.
{% tabs syncKey="install-method" %}
{% tabitem label="npm" %}
@@ -14,7 +17,7 @@ To install Nx on your machine, choose one of the following methods based on your
npm add --global nx
```
**Note:** You can also use `yarn`, `pnpm`, or `bun`
**Note:** You can also use `yarn global add nx`, `pnpm add --global nx`, or `bun add --global nx`
{% /tabitem %}
{% tabitem label="Homebrew (macOS, Linux)" %}
@@ -44,54 +47,80 @@ sudo apt install nx
{% /tabitem %}
{% /tabs %}
## Adding Nx to Your Repository
### Verify Installation
```shell
nx --version
```
You should see a version number like `22.5.0`.
### Update Global Installation
{% tabs syncKey="install-method" %}
{% tabitem label="npm" %}
```shell
npm update --global nx
```
**Note:** You can also use `yarn global upgrade nx`, `pnpm update --global nx`, or `bun update --global nx`
{% /tabitem %}
{% tabitem label="Homebrew (macOS, Linux)" %}
```shell
brew upgrade nx
```
{% /tabitem %}
{% tabitem label="Chocolatey (Windows)" %}
```shell
choco upgrade nx
```
{% /tabitem %}
{% tabitem label="apt (Ubuntu)" %}
```shell
sudo apt update
sudo apt upgrade nx
```
{% /tabitem %}
{% /tabs %}
## Install in a Repository
To add Nx to an existing repository, run:
```shell
nx init
npx nx@latest init
```
**Note:** You can also manually install the [`nx` NPM package](https://www.npmjs.com/package/nx) and create a [nx.json](/docs/reference/nx-json) to configure it.
Learn more about [adopting Nx in an existing project](/docs/guides/adopting-nx)
This installs the `nx` package as a dev dependency and creates an `nx.json` configuration file. If you have Nx installed globally, it will defer to the local version in your repository.
### Starter Repository
{% aside type="note" title="Manual Installation" %}
You can also manually install the [`nx` NPM package](https://www.npmjs.com/package/nx) and create an [nx.json](/docs/reference/nx-json) configuration file.
{% /aside %}
To create a starter repository, you can use the `create-nx-workspace` command. This will create a new Nx workspace with a default configuration and example applications.
### Update Nx in Your Repository
```shell
npx create-nx-workspace@latest
```
## Update Nx
When you update Nx, Nx will also [automatically update your dependencies](/docs/features/automate-updating-dependencies) if you have an [Nx plugin](/docs/concepts/nx-plugins) installed for that dependency. To update Nx, run:
When you update Nx in your repository, it will also [automatically update your dependencies](/docs/features/automate-updating-dependencies) if you have an [Nx plugin](/docs/concepts/nx-plugins) installed for that dependency. To update Nx, run:
```shell
nx migrate latest
```
This will create a `migrations.json` file with any update scripts that need to be run. Run them with:
This creates a `migrations.json` file with any update scripts that need to be run. Run them with:
```shell
nx migrate --run-migrations
```
{% aside type="tip" title="Update One Major Version at a Time" %}
{% aside type="note" title="Update One Major Version at a Time" %}
To avoid potential issues, it is [recommended to update one major version of Nx at a time](/docs/guides/tips-n-tricks/advanced-update#one-major-version-at-a-time-small-steps).
{% /aside %}
## Tutorials
Try one of these tutorials for a full walkthrough of what to do after you install Nx:
- [TypeScript Monorepo Tutorial](/docs/getting-started/tutorials/typescript-packages-tutorial)
- [React Monorepo Tutorial](/docs/getting-started/tutorials/react-monorepo-tutorial)
- [Angular Monorepo Tutorial](/docs/getting-started/tutorials/angular-monorepo-tutorial)
## More Documentation
- [Add Nx to an Existing Repository](/docs/guides/adopting-nx)
- [Update Nx](/docs/features/automate-updating-dependencies)
- [Update Your Global Nx Installation](/docs/guides/installation/update-global-installation)
- [Install Nx in a Non-Javascript Repo](/docs/guides/installation/install-non-javascript)
@@ -1,33 +1,46 @@
---
title: What is Nx?
description: 'Nx is an AI-first monorepo platform that connects everything from your editor to CI. Helping you deliver fast, without breaking things.'
description: 'Nx is a build system with smart caching and task orchestration for monorepos. Ship faster without breaking things.'
sidebar:
order: 1
label: Introduction
filter: 'type:Features'
---
Nx is a powerful, open-source, technology-agnostic **monorepo platform** designed to efficiently manage codebases of any scale. From small workspaces to large enterprise monorepos, Nx provides the tools to **efficiently get from starting a feature in your editor to a green PR**.
As teams and codebases grow, productivity bottlenecks multiply: build times increase, CI becomes flaky, and code sharing becomes complex. **Nx reduces friction across your entire development cycle.**
Nx is a build system for monorepos. It helps you **develop faster** and **keep CI fast** as your codebase scales.
{% youtube src="https://youtu.be/pbAQErStl9o" title="What is Nx?" width="100%" /%}
## Start small, extend as you grow
## Challenges of Monorepos
Nx is built in a modular fashion, allowing you to adopt as little or as much as you'd like at any moment in your development lifecycle. You can **start with just the core and add additional capabilities incrementally** as your needs grow and complexity increases.
Monorepos have many advantages and are especially powerful for AI-assisted development. But as teams and codebases grow, monorepos are hard to scale:
{% callout type="deepdive" title="Can I add Nx to a single-project repo?" %}
Yes, Nx provides value even for single-project repositories. You get fast task caching, intelligent task orchestration, and access to Nx plugins for your specific technology stack. As your project grows into a monorepo, the foundation is already in place.
- **Slow builds and tests** - Hundreds or thousands of tasks compete for CI resources.
- **Complex task pipelines** - Projects depend on each other, so tasks need to run in the right order, and that's hard to manage by hand.
- **Flaky CI** - Longer pipelines lead to random failures and inconsistent results between local and CI environments.
- **Architectural erosion** - Without clear boundaries, unwanted dependencies creep in and projects become tightly coupled.
Nx can also connect multiple repositories into a synthetic monorepo, letting you orchestrate large changes across all connected repos.
{% /callout %}
## What Nx Does
At the **foundation is Nx Core**, a Rust-based, technology-agnostic task runner. Nx Core creates a knowledge graph of your workspace, understanding project relationships and dependencies. This enables highly optimized and fast task execution regardless of technology stack. It runs `package.json` scripts in [TypeScript monorepos](/docs/technologies/typescript/introduction) or Gradle tasks in [Java projects](/docs/technologies/java/introduction) or [can be extended](/docs/extending-nx/intro) to meet your project's specific needs.
**Nx reduces friction across your entire development cycle** with intelligent caching, task orchestration, and deep understanding of your codebase structure.
{% callout type="deepdive" title="What do you mean by \"running NPM scripts\"?" %}
At its core, Nx:
At the very core, Nx is a super fast, intelligent task runner. Let's take the example of an NPM workspace. This could be a project's `package.json`:
1. **Runs tasks fast** - [Caches results](/docs/features/cache-task-results) so you never rebuild the same code twice.
2. **Understands your codebase** - Builds [project and task graphs](/docs/features/explore-graph) showing how everything connects.
3. **Orchestrates intelligently** - Runs tasks in the [right order](/docs/concepts/task-pipeline-configuration), parallelizing when possible.
4. **Enforces boundaries** - [Module boundary rules](/docs/features/enforce-module-boundaries) prevent unwanted dependencies between projects.
5. **Handles flakiness** - [Automatically re-runs flaky tasks](/docs/features/ci-features/flaky-tasks) and [self-heals CI failures](/docs/features/ci-features/self-healing-ci).
```shell
nx build myapp # Run a task
nx build myapp # Run again - instant cache hit
nx run-many -t build test # Run across all projects
```
{% callout type="deepdive" title="How does Nx run tasks?" %}
At its core, Nx is a fast, intelligent task runner. Take the example of an NPM workspace. This could be a project's `package.json`:
```json
// package.json
@@ -40,7 +53,7 @@ At the very core, Nx is a super fast, intelligent task runner. Let's take the ex
}
```
Then you can simply add Nx to your root `package.json`:
Then add Nx to your root `package.json`:
```json
// package.json
@@ -59,33 +72,50 @@ nx build my-project
This will execute the `build` script from `my-project`'s `package.json`, equivalent to running `npm run build` in that project directory.
Similarly you [can run tasks across all projects](/docs/features/run-tasks), just specific ones or just those from projects you touched.
Similarly you [can run tasks across all projects](/docs/features/run-tasks), specific ones, or only those from projects you touched.
From there, you can gradually enhance your setup by adding features like [task caching](/docs/features/cache-task-results), adding [plugins](/docs/technologies), optimizing your CI via [task distribution](/docs/features/ci-features/distribute-task-execution), and many more powerful capabilities as your needs grow.
From there, you can gradually enhance your setup by adding features like [task caching](/docs/features/cache-task-results), adding [plugins](/docs/plugin-registry), optimizing your CI via [task distribution](/docs/features/ci-features/distribute-task-execution), and many more powerful capabilities as your needs grow.
{% /callout %}
Nx Core provides everything you need to get started and works perfectly on its own.
**When you're ready for more, the Nx monorepo platform offers additional capabilities you can adopt incrementally**.
Extend your setup with [**Nx Cloud**](/docs/getting-started/nx-cloud) for remote caching, distributed task execution, and [**AI-powered self-healing CI**](/docs/features/ci-features/self-healing-ci) that automatically detects, analyzes, and fixes CI failures.
Integrate [**Nx Console**](/docs/getting-started/editor-setup) with your editor for powerful autocomplete, project graph visualization, CI notifications, and an MCP to [make your AI coding assistant smarter](/docs/features/enhance-ai).
Add [**Nx Plugins**](/docs/technologies) for technology-specific automation and DX improvements, or build custom platform capabilities using [Nx Devkit](/docs/extending-nx/intro).
## Start Small, Grow as Needed
## Where to go from here?
Nx is modular. Start with the CLI and add capabilities as your needs grow.
| Component | What It Does |
| ---------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Nx Core** | Task runner with [local caching](/docs/features/cache-task-results). Works with any tech stack. |
| [**Nx Plugins**](/docs/plugin-registry) | Technology-specific automation (generators, executors, dependency detection). |
| [**Nx Console**](/docs/getting-started/editor-setup) | Editor extension for VSCode/JetBrains with visual UI and [AI assistance](/docs/features/enhance-ai). |
| [**Nx Cloud**](/docs/features/ci-features) | [Remote caching](/docs/features/ci-features/remote-cache), [affected commands](/docs/features/ci-features/affected), and [self-healing CI](/docs/features/ci-features/self-healing-ci). |
{% callout type="deepdive" title="Can I add Nx to a single-project repo?" %}
Yes, Nx provides value even for single-project repositories. You get fast task caching, intelligent task orchestration, and access to Nx plugins for your specific technology stack. As your project grows into a monorepo, the foundation is already in place.
Nx can also connect multiple repositories into a synthetic monorepo, letting you orchestrate large changes across all connected repos.
{% /callout %}
## Where to Go from Here
{% callout type="note" title="Choose Your Path" %}
**Starting fresh?** → [Create a new workspace](/docs/getting-started/start-new-project)
**Have an existing project?** → [Add Nx to your project](/docs/getting-started/start-with-existing-project)
**Want hands-on learning?** → [Follow a tutorial](/docs/getting-started/tutorials)
**Prefer video?** → [Learn with our video courses](https://nx.dev/courses)
{% /callout %}
{% cardgrid %}
{% linkcard title="Nx quickstart" description="Dive right in with our quickstart steps to create your first project or add Nx to your existing one." href="/docs/quickstart" /%}
{% linkcard title="Quickstart" description="Get your first Nx project running in minutes." href="/docs/quickstart" /%}
{% linkcard title="Explore Technologies" description="Explore Nx's technology integrations and how it can support your specific stack." href="/docs/technologies" /%}
{% linkcard title="Plugins" description="Find plugins for React, Angular, Node, Gradle, Maven, .NET, and more." href="/docs/plugin-registry" /%}
{% linkcard title="Step by step with our tutorials" description="Learn more about Nx through hands-on tutorials for different technology stacks." href="/docs/getting-started/tutorials" /%}
{% linkcard title="Concepts" description="Improve your understanding of how Nx works under the hood." href="/docs/concepts" /%}
{% linkcard title="Learn with our video courses" description="Dive deeper with comprehensive video courses that walk you through Nx concepts." href="https://nx.dev/courses" /%}
{% linkcard title="Dive deep into Nx features" description="Discover all the powerful features that Nx provides to streamline your workflow." href="/docs/features" /%}
{% linkcard title="Understand underlying concepts" description="Improve your understanding of the core concepts of how Nx works under the hood." href="/docs/concepts" /%}
{% linkcard title="Features" description="Explore Nx features like caching, task orchestration, and CI optimization." href="/docs/features" /%}
{% /cardgrid %}
@@ -6,7 +6,7 @@ filter: 'type:Features'
{% youtube src="https://www.youtube.com/watch?v=cDBihpB3SbI" title="Nx and Nx Cloud" width="100%" /%}
CI is challenging and it's **not your fault**. It's a fundamental issue with how the current, traditional CI execution model works. Nx Cloud adopts a new **task-based** CI model which allows you to overcome slowness and unreliability of the current VM-based CI model.
CI is challenging and it's **not your fault**. It's a fundamental issue with how the current, traditional CI execution model works. Nx Cloud adopts a new **task-based** CI model that overcomes slowness and unreliability of the current VM-based CI model.
_(Dive deeper into the [task based CI execution model](https://nx.dev/blog/reliable-ci-a-new-execution-model-fixing-both-flakiness-and-slowness))_
Nx Cloud improves many aspects of the CI/CD process:
@@ -17,7 +17,7 @@ Nx Cloud improves many aspects of the CI/CD process:
## Connect your workspace to Nx Cloud
The most straightforward way to connect your Nx workspace with Nx Cloud is via the web application:
To connect your Nx workspace with Nx Cloud, use the web application:
{% call_to_action variant="default" title="Create a new or connect an existing repo" url="https://cloud.nx.app/get-started?utm_source=nx-dev&utm_medium=nx-cloud_intro&utm_campaign=try-nx-cloud" description="Setup takes less than 2 minutes" /%}
@@ -1,77 +1,48 @@
---
title: Start a new project with Nx
description: Create a new Nx workspace manually with your favorite CLI or use the guided setup with presets for various technology stacks and configurations.
title: Start a New Project
description: Create a new Nx workspace with starter templates or via Nx Cloud in the browser.
sidebar:
label: Start a new project
label: Start a New Project
order: 3
filter: 'type:Guides'
---
When you start a new project with Nx, you have two options: manual or guided.
Create a new Nx workspace using one of these options:
## Option 1: Manual setup
- **[Option 1: Create locally with templates](#option-1-create-locally-with-templates)** - Run a command to scaffold a new monorepo on your machine
- **[Option 2: Create via Nx Cloud](#option-2-create-via-nx-cloud)** - Use the browser-based setup with CI/CD pre-configured
In a nutshell, this means using your favorite CLI to create your initial project setup and then adding Nx to it.
Let's take the example of an NPM workspace. Create a new root-level `package.json` like:
```json
// package.json
{
"name": "my-workspace",
"version": "1.0.0",
"private": true,
"workspaces": ["packages/*", "apps/*"]
}
```
Then you can add Nx to it by using:
```shell
nx@latest init
```
{% aside type="note" title="Global Installs" %}
Make sure you have [Nx installed globally](/docs/getting-started/installation) or use `npx` if you're in a JavaScript environment
{% aside type="note" title="Adding Nx to an existing project?" %}
If you already have a project and want to add Nx to it, see [Add to an Existing Project](/docs/getting-started/start-with-existing-project) instead.
{% /aside %}
Nx will detect the underlying workspace configuration, ask you a couple of questions and install itself into the workspace. You can now [run tasks with Nx](/docs/features/run-tasks) and incrementally add functionality, like:
## Option 1: Create Locally with Templates
- [Configure caching](/docs/features/cache-task-results)
- [Adding Nx plugins to help refine your workflows](/docs/plugin-registry)
- [Optimizing your CI](/docs/guides/nx-cloud/setup-ci)
## Option 2: Create a new workspace with presets
Alternatively, you can choose a more guided approach by leveraging some of the presets Nx comes with.
Run the following command to get started:
Run the following command to create a new Nx workspace:
```shell
npx create-nx-workspace@latest
```
This interactive command will guide you through the setup process, allowing you to:
This interactive command guides you through the setup:
- **Choose your workspace name** - This will be the name of your root directory
- **Select your preferred package manager** - npm, yarn, or pnpm
- **Pick a preset** - Choose from [various technology stacks and configurations](/docs/reference/create-nx-workspace#presets)
- **Configure additional options** - Such as styling solutions, testing frameworks, and more
- **Workspace name** - The name of your root directory
- **Template** - Choose from [various technology stacks](/docs/reference/create-nx-workspace#presets) (React, Angular, Node, etc.)
- **Package manager** - npm, yarn, pnpm, or bun
- **Additional options** - Styling, testing frameworks, and more depending on your template
Choose a preset that matches your technology stack. This gives you a fully configured workspace.
For a minimal setup, choose the **empty workspace** template (`--preset=ts`). This gives you a bare TypeScript monorepo that you can extend incrementally.
You can also choose **an empty workspace preset** (`--preset=ts`) which sets up the bare minimum configuration for TypeScript and Nx. This allows you to add technologies and features incrementally over time as you need them.
## Option 3: Get the complete Nx monorepo platform experience
## Option 2: Create via Nx Cloud
[![Nx Cloud onboarding](../../../assets/getting-started/nx-cloud-starting-screen.avif)](https://cloud.nx.app/get-started?utm_source=nx-docs&utm_medium=nx-cloud-onboarding&utm_campaign=start-new-project)
For the complete experience, you can also get [started directly from the Nx Cloud application](https://cloud.nx.app/get-started?utm_source=nx-docs&utm_medium=nx-cloud-onboarding&utm_campaign=start-new-project).
[Create your workspace directly from Nx Cloud](https://cloud.nx.app/get-started?utm_source=nx-docs&utm_medium=nx-cloud-onboarding&utm_campaign=start-new-project) for a browser-based setup experience.
This approach gives you a fully end-to-end development workflow right from the start, making it easy to get up and running when your project is in its initial phase.
You'll get a fully working CI configuration that includes Nx Cloud's AI-powered features like **AI-powered self-healing CI** that automatically fixes common CI failures.
This means you benefit from intelligent automation right from day one, without having to configure complex CI pipelines manually.
This option gives you:
As your project grows and scales, you'll have access to additional features like **remote caching** to speed up builds across your team, **distributed task execution with Nx Agents** to parallelize work across multiple machines, and **automatic test splitting** to optimize your CI pipeline performance.
- A working CI configuration out of the box
- [Remote caching](/docs/features/ci-features/remote-cache) enabled from the start
- [Self-healing CI](/docs/features/ci-features/self-healing-ci) that automatically fixes common failures
[Get started with the complete Nx monorepo platform experience →](https://cloud.nx.app/get-started?utm_source=nx-docs&utm_medium=nx-cloud-onboarding&utm_campaign=start-new-project)
[Get started with Nx Cloud →](https://cloud.nx.app/get-started?utm_source=nx-docs&utm_medium=nx-cloud-onboarding&utm_campaign=start-new-project)
@@ -1,102 +1,49 @@
---
title: Start with an existing project
description: Add Nx to any existing project with a single command. Start with Nx Core and gradually adopt plugins, CI integrations, and other capabilities.
title: Add to an Existing Project
description: Add Nx to any existing project with a single command. Start with task running and caching, then gradually adopt more capabilities.
sidebar:
order: 4
label: Add to existing project
label: Add to Existing Project
filter: 'type:Guides'
---
{% course_video src="https://youtu.be/3hW53b1IJ84" courseTitle="From PNPM Workspaces to Distributed CI" courseUrl="https://nx.dev/courses/pnpm-nx-next/lessons-01-nx-init" /%}
In many situations, you have an existing codebase and want to improve it with Nx using an **incremental adoption approach**.
Nx is designed for incremental adoption. Start with task running and [caching](/docs/features/cache-task-results), then add [plugins](/docs/technologies), [CI integrations](/docs/guides/nx-cloud/setup-ci), or other capabilities as your needs grow.
Thanks to [Nx's modular architecture](/docs/getting-started/intro), you can start with just **Nx Core** and then gradually add [technology-specific plugins](/docs/technologies), [CI integrations](/docs/getting-started/nx-cloud), or other capabilities as your requirements evolve.
Getting started is remarkably simple. You can add Nx to any existing project with a single command:
Add Nx to any existing project with a single command:
```shell
nx@latest init
npx nx@latest init
```
{% aside type="note" title="Global Installs" %}
Make sure you have [Nx installed globally](/docs/getting-started/installation) or use `npx` if you're in a JavaScript environment
{% /aside %}
Whether a monorepo, single project or something in between, `nx init` walks you through adding and configuring Nx. You can pick a minimal approach or detailed guided setup. At the end you'll have an Nx workspace ready for anything!
Whether a monorepo, single project, or something in between, `nx init` walks you through adding and configuring Nx. At the end you'll have an Nx workspace ready for anything.
## Next Steps
After initializing Nx, you can [run tasks](/docs/features/run-tasks) with `nx <task> <project-name>` (e.g. `nx build myproject`) or run one or many tasks across all projects with `nx run-many -t <task1> <task2>`.
After initializing Nx, try these commands:
You can also explore your codebase using:
- `nx graph` to view an interactive graph
- `nx show projects` to see a list of all projects
- `nx show project <project-name>` to view an interactive project detailed view
### Update CI Configurations
Now that Nx is installed, you'll want to update CI configurations to leverage Nx. You can do this by changing previous commands to use `nx` instead.
For example, switching from `pnpm` commands to use `nx`
```diff
// .github/workflows/ci.yaml
- - run: pnpm run -r build
- - run: pnpm run -r test
+ - run: npx nx run-many -t test build
```shell
nx build <project-name> # Run a task
nx build <project-name> # Run again - instant cache hit
nx run-many -t build test # Run tasks across all projects
nx graph # Visualize project dependencies
```
You can directly invoke `package.json` scripts with `nx` as well
From here you can:
```diff
// .github/workflows/ci.yaml
- - run: npm run build
- - run: npm run test
+ - run: npx nx build
+ - run: npx nx test
```
- [Configure task caching](/docs/features/cache-task-results) to speed up repeated builds
- [Add Nx plugins](/docs/technologies) for your tech stack (React, Angular, Node, etc.)
- [Set up CI](/docs/guides/nx-cloud/setup-ci) with remote caching and affected commands
- Enable [remote caching](/docs/features/ci-features/remote-cache) with `nx connect`
[View CI provider specific setups](/docs/guides/nx-cloud/setup-ci) to learn more.
### Nx Cloud
{% aside type="note" title="How do I know if I enabled Nx Cloud?" %}
Validate Nx Cloud is enabled by checking the `nx.json` file for `nxCloudId` property.
You can add Nx Cloud at any point by running the `nx connect` command.
{%/aside%}
After initializing Nx, you'll need to commit and push the changes to your repository.
Once your changes are pushed, you can finish setting up your workspace by clicking on the list printed to your terminal, or by visiting [Nx Cloud directly](https://cloud.nx.app/get-started?utm_source=nx.dev&utm_campaign=nx_init) and clicking _"Connect an existing Nx repository"_
To leverage Self Healing CI, you'll need to add the following to your CI configuration:
```diff
// .github/workflows/ci.yaml
- run: npx nx run-many -t lint test build
+ # Enable Self Healing CI w/ Nx Cloud
+ - run: npx nx fix-ci
+ if: always()
```
### Empower Your Editor
Enhance your developer experience by using the Nx Console editor extension.
{% install_nx_console /%}
## In-depth Guides
Here are some guides that give you more details based on the technology stack you're using:
## In-Depth Guides
{% cardgrid %}
{% linkcard title="Add to Existing Monorepo"
href="/docs/guides/adopting-nx/adding-to-monorepo" %}
{% /linkcard %}
{% linkcard title="Add to Any Project" href="/docs/guides/adopting-nx/adding-to-existing-project" /%}
{% linkcard title="Add to Existing Monorepo" href="/docs/guides/adopting-nx/adding-to-monorepo" /%}
{% linkcard title="Add to Any Project" href="/docs/guides/adopting-nx/adding-to-existing-project" /%}
{% linkcard title="Migrate from Angular CLI" href="/docs/technologies/angular/migration/angular" /%}
@@ -107,7 +107,7 @@ This plugin system helps teams scale organizationally by:
Nx has been battle-tested since 2016:
- ~5 million downloads per week
- ~9 million downloads per week
- Nearly 2 million unique [Nx Console](https://marketplace.visualstudio.com/items?itemName=nrwl.angular-console) installations
- Rich ecosystem of [third-party plugins](/docs/plugin-registry), many with millions of downloads in their own right
- Used by over half of Fortune 500 companies in production
@@ -12,6 +12,10 @@ Nx errs on the side of caution when using inputs. Ideally, the "perfect" configu
For an overview of all the possible [types of inputs](/docs/reference/inputs) and how to reuse sets of inputs as [named inputs](/docs/reference/inputs#named-inputs), see the reference documentation.
{% aside type="caution" title="Directory Paths Require Trailing Slash or Glob" %}
When specifying a directory as an input, you must use a trailing slash (`/`) or a glob pattern. For example, `{projectRoot}/src/` or `{projectRoot}/src/**/*` will match all files in the `src` directory, but `{projectRoot}/src` (without trailing slash) will not match any files. This differs from `outputs`, which support naked directory paths.
{% /aside %}
Throughout this recipe, the following project structure of a simple workspace will be used as an example to help understand inputs better.
{% graph height="450px" %}
@@ -4,6 +4,10 @@ description: 'Learn how to generate package.json and pruned lock files for your
filter: 'type:Guides'
---
{% aside type="note" title="Using TS Solution Setup?" %}
If your workspace uses TS project references (the default in Nx 20+), use the [prune workflow](/docs/technologies/node/guides/deploying-node-projects) instead. The `generatePackageJson` approach below applies to workspaces without TS Solution Setup.
{% /aside %}
A common approach to deploying applications is via docker containers. Some applications can be built into bundles that are environment agnostic, while others depend on OS-specific packages being installed. For these situations, having just bundled code is not enough, we also need to have `package.json`.
Nx supports the generation of the project's `package.json` by identifying all the project's dependencies. The generated `package.json` is created next to the built artifacts (usually at `dist/apps/name-of-the-app`).
@@ -0,0 +1,9 @@
---
title: How Nx Works
description: Core concepts and mental models behind Nx
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="How Nx Works" /%}
@@ -0,0 +1,9 @@
---
title: Angular
description: Angular guides and best practices for Nx workspaces
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Knowledge Base/Angular" /%}
@@ -0,0 +1,9 @@
---
title: Benchmarks
description: Performance benchmarks for Nx
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Knowledge Base/Benchmarks" /%}
@@ -0,0 +1,9 @@
---
title: Continuous Integration
description: Set up and configure CI pipelines with Nx
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Knowledge Base/Continuous Integration" /%}
@@ -0,0 +1,9 @@
---
title: Creating Releases
description: Guides for creating and publishing releases with Nx
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Knowledge Base/Creating Releases" /%}
@@ -0,0 +1,9 @@
---
title: Cypress
description: Cypress guides and best practices for Nx workspaces
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Knowledge Base/Cypress" /%}
@@ -0,0 +1,9 @@
---
title: .NET
description: .NET guides and best practices for Nx workspaces
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Knowledge Base/.NET" /%}
@@ -0,0 +1,9 @@
---
title: ESLint
description: ESLint guides and best practices for Nx workspaces
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Knowledge Base/ESLint" /%}
@@ -0,0 +1,9 @@
---
title: Extending Nx
description: Guides for extending Nx with custom plugins, generators, and executors
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Knowledge Base/Extending Nx" /%}
@@ -0,0 +1,9 @@
---
title: Knowledge Base
description: In-depth guides, recipes, and technology-specific documentation for Nx
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Knowledge Base" /%}
@@ -0,0 +1,9 @@
---
title: Installation
description: Installation guides for Nx
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Knowledge Base/Installation" /%}
@@ -0,0 +1,9 @@
---
title: Module Federation
description: Module Federation guides and best practices for Nx workspaces
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Knowledge Base/Module Federation" /%}
@@ -0,0 +1,9 @@
---
title: Node
description: Node.js guides and best practices for Nx workspaces
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Knowledge Base/Node" /%}
@@ -0,0 +1,9 @@
---
title: Nx Console
description: Guides for using Nx Console IDE extension
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Knowledge Base/Nx Console" /%}
@@ -0,0 +1,9 @@
---
title: Organizational Decisions
description: Guidance on monorepo organizational decisions
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Knowledge Base/Organizational Decisions" /%}
@@ -0,0 +1,9 @@
---
title: Playwright
description: Playwright guides and best practices for Nx workspaces
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Knowledge Base/Playwright" /%}
@@ -0,0 +1,9 @@
---
title: React
description: React guides and best practices for Nx workspaces
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Knowledge Base/React" /%}
@@ -0,0 +1,9 @@
---
title: Recipes
description: Practical recipes and tips for Nx workspaces
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Knowledge Base/Recipes" /%}
@@ -0,0 +1,9 @@
---
title: Storybook
description: Storybook guides and best practices for Nx workspaces
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Knowledge Base/Storybook" /%}
@@ -0,0 +1,9 @@
---
title: Tasks & Caching
description: Guides for configuring tasks and caching in Nx
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Knowledge Base/Tasks & Caching" /%}
@@ -0,0 +1,9 @@
---
title: Troubleshooting
description: Common issues and solutions for Nx workspaces
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Knowledge Base/Troubleshooting" /%}
@@ -0,0 +1,9 @@
---
title: TypeScript
description: TypeScript guides and best practices for Nx workspaces
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Knowledge Base/TypeScript" /%}
@@ -0,0 +1,9 @@
---
title: Vite
description: Vite guides and best practices for Nx workspaces
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Knowledge Base/Vite" /%}
@@ -0,0 +1,9 @@
---
title: Vitest
description: Vitest guides and best practices for Nx workspaces
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Knowledge Base/Vitest" /%}
@@ -0,0 +1,9 @@
---
title: Vue
description: Vue guides and best practices for Nx workspaces
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Knowledge Base/Vue" /%}
@@ -0,0 +1,9 @@
---
title: Webpack
description: Webpack guides and best practices for Nx workspaces
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Knowledge Base/Webpack" /%}
@@ -0,0 +1,9 @@
---
title: Enforce Module Boundaries
description: Enforce constraints on project dependencies in your workspace
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Platform Features/Code Organization/Enforce Module Boundaries" /%}
@@ -0,0 +1,9 @@
---
title: Code Organization
description: Tools and features for organizing code in your Nx workspace
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Platform Features/Code Organization" /%}
@@ -0,0 +1,9 @@
---
title: Conformance Reference
description: Reference documentation for Nx conformance rules
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Platform Features/Enterprise/Conformance Reference" /%}
@@ -0,0 +1,9 @@
---
title: Enterprise
description: Enterprise features for Nx Cloud
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Platform Features/Enterprise" /%}
@@ -0,0 +1,9 @@
---
title: Single Tenant
description: Single tenant deployment guides for Nx Cloud
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Platform Features/Enterprise/Single Tenant" /%}
@@ -0,0 +1,9 @@
---
title: Platform Features
description: Explore all the powerful features that Nx provides
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Platform Features" /%}
@@ -0,0 +1,9 @@
---
title: Maintenance
description: Guides for maintaining and upgrading your Nx workspace
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Platform Features/Maintenance" /%}
@@ -0,0 +1,9 @@
---
title: Orchestration & CI
description: Features for orchestrating tasks and optimizing CI pipelines with Nx
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Platform Features/Orchestration & CI" /%}
@@ -0,0 +1,9 @@
---
title: Release & Publishing
description: Tools for managing releases and publishing packages with Nx
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Platform Features/Release & Publishing" /%}
@@ -208,6 +208,7 @@ If you are using MinIO earlier than `2024-07-04T14-25-45Z` it is recommended to
| **accessKeyId** | AWS Access Key ID (optional if `AWS_ACCESS_KEY_ID` is set in the environment) |
| **secretAccessKey** | AWS secret access key (optional if `AWS_SECRET_ACCESS_KEY` is set in the environment) |
| **disableChecksum** | This disables AWS' checksum validation for cache entries |
| **cacheKeyPrefix** | Prefix added to cache keys |
By default, Nx will try to write and read from the remote cache while running locally. This means that permissions must be set for users who are expected to access the remote cache.
@@ -237,6 +238,19 @@ The cache mode in CI can also be configured by setting `ciMode` to `read-only` o
}
```
# Cache Key Prefix
The `cacheKeyPrefix` setting enables you to add a prefix to your cache keys, making it possible to store multiple projects or environments within the same storage bucket.
```jsonc
// nx.json
{
"s3": {
"cacheKeyPrefix": "designSystem",
},
}
```
### Migrating from Custom Tasks Runners
Many people who are interested in Nx caching plugins have previously used custom task runners. Nx offers a new and simpler extension API designed to meet the same use cases as the now-deprecated custom task runners.
@@ -0,0 +1,9 @@
---
title: Angular
description: Angular API reference for Nx plugins
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Reference/Angular" /%}
@@ -0,0 +1,9 @@
---
title: Cypress
description: Cypress API reference for Nx plugins
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Reference/Cypress" /%}
@@ -0,0 +1,9 @@
---
title: Detox
description: Detox API reference for Nx plugins
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Reference/Detox" /%}
@@ -0,0 +1,9 @@
---
title: .NET
description: .NET API reference for Nx plugins
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Reference/.NET" /%}
@@ -0,0 +1,9 @@
---
title: ESBuild
description: ESBuild API reference for Nx plugins
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Reference/ESBuild" /%}
@@ -0,0 +1,9 @@
---
title: ESLint
description: ESLint API reference for Nx plugins
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Reference/ESLint" /%}
@@ -50,6 +50,25 @@ Alternatively, you can use the object format with the `fileset` property:
}
```
#### Directory Paths
When specifying a directory as an input, you must use a trailing slash or a glob pattern. A path without a trailing slash or glob pattern will be treated as a file path and will not match any files within the directory.
```jsonc
// nx.json
{
"inputs": [
"{projectRoot}/src/", // ✓ Matches all files in src (note the trailing slash)
"{projectRoot}/src/**/*", // ✓ Matches all files in src using glob
"{projectRoot}/src", // ✗ Does NOT match files - treated as a file path
],
}
```
{% aside type="note" title="Difference from Outputs" %}
This behavior differs from `outputs`, which support naked directory paths without a trailing slash. For example, `{projectRoot}/dist` works as an output but would not work as an input.
{% /aside %}
#### Token Behavior with Nested Projects
These tokens behave differently when dealing with nested projects:
@@ -0,0 +1,9 @@
---
title: Java
description: Java API reference for Nx plugins
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Reference/Java" /%}
@@ -0,0 +1,9 @@
---
title: Jest
description: Jest API reference for Nx plugins
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Reference/Jest" /%}
@@ -0,0 +1,9 @@
---
title: Module Federation
description: Module Federation API reference for Nx plugins
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Reference/Module Federation" /%}
@@ -0,0 +1,9 @@
---
title: Node
description: Node.js API reference for Nx plugins
sidebar:
hidden: true
pagefind: false
---
{% sidebar_group_cards group="Reference/Node" /%}
@@ -1,38 +0,0 @@
---
title: Node.js and TypeScript Compatibility
description: A reference outlining Nx's support policy and current compatibility matrix for Node.js and TypeScript.
filter: 'type:References'
---
## Node.js Compatibility Matrix
Below is a reference table that matches the most recent major versions of Nx to the versions of Node.js that they officially support, and are tested against.
Nx's policy is to support the LTS versions (i.e. actively maintained even numbered versions) of Node.js, but we will only remove support for older versions in a major version of Nx to avoid unexpected disruption. We may add support for newer LTS versions in a minor version of Nx as long as it would not break existing projects.
> _Note: Other versions of Node.js **may** still work without issue for these versions of Nx. Those include versions which are already EOL, or odd version numbers (e.g. 23), which Node.js actively
> discourages using in production._
| Nx Version | Node Version |
| --------------- | ------------------------ |
| 22.x (current) | 24.x, ^22.12.0, ^20.19.0 |
| 21.x (previous) | 24.x, ^22.12.0, ^20.19.0 |
| 20.x | 22.x, 20.x, 18.x |
| 19.x | 22.x, 20.x, 18.x |
| 18.x | 20.x, 18.x |
We intentionally do not include an `"engines"` field in the `package.json` file for Nx in order to allow for user flexibility, but this page should be considered the official compatibility matrix.
## TypeScript Compatibility
Unlike Node.js, TypeScript's policy is not to follow semver conventions around breaking changes only coming in major versions, despite using version numbers that are semver-like. Just like with Node.js, though, we will only remove support for older versions of TypeScript in a major version of Nx to avoid unexpected disruption. We may add support for newer versions in a minor version of Nx as long as it would not break existing projects.
| Nx Version | TypeScript Version |
| --------------- | ------------------ |
| 22.x (current) | >= 5.4.2 < 5.10.0 |
| 21.x (previous) | >= 5.4.2 < 5.10.0 |
| 20.x | ~5.4.2 |
| 19.x | ~5.4.2 |
| 18.x | ~5.4.2 |
This page will be updated from time to time to reflect the latest versions of Node.js and TypeScript that are supported. If you encounter issues with Nx, please make sure you are using a supported version of Node.js and TypeScript before filing an issue.
@@ -136,6 +136,48 @@ Plugins use config files to infer tasks for projects. You can specify which conf
The `include` and `exclude` properties are each file glob patterns that are used to include or exclude the configuration file that the plugin is interpreting. In the example provided, the `@nx/jest/plugin` plugin will only infer tasks for projects where the `jest.config.ts` file path matches the `packages/**/*` glob but does not match the `**/*-e2e/**/*` glob.
#### Using Negation Patterns
You can use negation patterns (patterns starting with `!`) to create more precise include/exclude rules. Patterns are processed in order, with later patterns overriding earlier ones.
**Example: Excluding all e2e projects except one**
```jsonc
// nx.json
{
"plugins": [
{
"plugin": "@nx/jest/plugin",
"exclude": ["**/*-e2e/**/*", "!**/toolkit-workspace-e2e/**/*"],
},
],
}
```
This will exclude all e2e projects except `toolkit-workspace-e2e`.
**Example: Including packages except legacy ones**
```jsonc
// nx.json
{
"plugins": [
{
"plugin": "@nx/vite/plugin",
"include": ["packages/**/*", "!packages/legacy/**/*"],
},
],
}
```
**How negation patterns work:**
- Patterns are processed in order from first to last
- A pattern starting with `!` removes files from the match set
- A pattern without `!` adds files to the match set
- The last matching pattern determines if a file is included
- If the first pattern is a negation, all files are matched initially
## Task Options
The following properties affect the way Nx runs tasks and can be set at the root of `nx.json`.
@@ -422,13 +464,27 @@ Release tag configuration now uses a nested `releaseTag` object. Old flat proper
#### Configuration Options
| Property | Type | Default | Description |
| ------------------------ | ------- | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| **pattern** | string | `v{version}` for fixed, `{projectName}@{version}` for independent | The git tag pattern to use. Supports interpolation of `{version}`, `{projectName}`, and `{releaseGroupName}` |
| **requireSemver** | boolean | `false` | Whether to require that all tags match semantic versioning |
| **strictPreid** | boolean | `false` for independent, `true` for fixed release groups | Whether to ensure prerelease IDs are consistent across packages |
| **preferDockerVersion** | boolean | `false` | Whether to prefer Docker-compatible version format in git tags |
| **checkAllBranchesWhen** | string | undefined | Branch to check when resolving current versions from git tags |
| Property | Type | Default | Description |
| ------------------------ | ------------------- | ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **pattern** | string | `v{version}` for fixed, `{projectName}@{version}` for independent | The git tag pattern to use. Supports interpolation of `{version}`, `{projectName}`, and `{releaseGroupName}` |
| **requireSemver** | boolean | `false` | Whether to require that all tags match semantic versioning |
| **strictPreid** | boolean | `false` for independent, `true` for fixed release groups | Whether to ensure prerelease IDs are consistent across packages |
| **preferDockerVersion** | boolean | `false` | Whether to prefer Docker-compatible version format in git tags |
| **checkAllBranchesWhen** | boolean \| string[] | undefined | Controls whether to check all branches or only merged branches when resolving current versions from git tags. `true` = always check all branches, `false` = only check the current branch, `string[]` = check all branches when the current branch matches any of the provided names or glob patterns |
#### Branch Resolution for Git Tags
The `checkAllBranchesWhen` option controls how Nx resolves existing git tags to determine the current version of your projects.
By default, Nx checks for matching tags on the current branch. If no tags are found, it falls back to checking all branches.
| Value | Behavior |
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `true` | Always check all branches for the latest matching tag |
| `false` | Only check the current branch (no fallback to all branches) |
| `string[]` | Check all branches when the current branch matches any of the provided names or [glob patterns](https://github.com/isaacs/minimatch). Otherwise, use the default behavior |
This option is useful when release tags may exist on multiple branches. Setting `checkAllBranchesWhen` to `true` or to a list of branch patterns ensures Nx finds the latest tag regardless of which branch it was created on.
#### Tag Pattern Syntax
@@ -459,7 +515,7 @@ Example patterns and their results:
"requireSemver": true,
"strictPreid": true,
"preferDockerVersion": false,
"checkAllBranchesWhen": "main",
"checkAllBranchesWhen": ["main", "release/*"],
},
},
}
@@ -476,7 +532,7 @@ Example patterns and their results:
"releaseTagPatternRequireSemver": true,
"releaseTagPatternStrictPreid": true,
"releaseTagPatternPreferDockerVersion": false,
"releaseTagPatternCheckAllBranchesWhen": "main",
"releaseTagPatternCheckAllBranchesWhen": ["main", "release/*"],
},
}
```

Some files were not shown because too many files have changed in this diff Show More