Compare commits

...

80 Commits

Author SHA1 Message Date
Jason Jean b05d5fee28 chore(core): retrigger ci 2026-02-27 08:46:40 -05:00
nx-cloud[bot] 14c2d5ba3f test(core): update tests for new PluginCache API
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>
2026-02-27 13:28:28 +00:00
Jason Jean c43ee13eed feat(core): add safe plugin cache write utilities with LRU eviction
Add PluginCache<T> class with explicit get/set API that tracks access
order for LRU eviction. Dedup and capping happen at write time, not
per-access. All plugin cache writes are now wrapped in try/catch so
failures never crash the project graph calculation.

Migrated consumers: cypress, playwright, dotnet, gradle (v1+v2),
maven, package-json, js/lockfile, nx-deps-cache.
2026-02-27 00:22:49 -05:00
Leosvel Pérez Espinosa af07e75d58 feat(core): use jemalloc with tuned decay timers for native module (#34444)
## Current Behavior

The Nx native module (Rust cdylib loaded by Node.js) uses the system
allocator. The daemon process retains a large RSS footprint after the
initial project graph build, even though most of that memory is no
longer in use. On macOS and Linux, the system allocator doesn't
aggressively return freed pages to the OS.

## Expected Behavior

The daemon's steady-state RSS drops significantly after graph build by
using jemalloc with tuned page purge timers. Peak RSS and wall time are
unaffected.

## Changes

Adds [tikv-jemallocator](https://github.com/tikv/jemallocator) as the
global allocator on Linux and macOS, with two compile-time settings:

- **`dirty_decay_ms:1000`** — returns freed pages to the OS after 1s
instead of the default 10s. Tuned to Nx's phase-separated workload
(graph build → idle → task execution), where transitions happen every
~30-60s. Benchmarked against 5s and 10s — both too slow to purge between
phases.
- **`muzzy_decay_ms:0`** — skips the lazy purge phase (`MADV_FREE`) and
goes straight to `MADV_DONTNEED`. Required on macOS and Linux ≥ 4.5
where `MADV_FREE` doesn't actually reduce RSS.

Windows and WASI continue using the system allocator. Windows is
excluded because `tikv-jemalloc-sys` fails to build with MSVC (spaces in
`cl.exe` path break the autoconf configure script). Tracked upstream in
[tikv/jemallocator#99](https://github.com/tikv/jemallocator/pull/99).

### Other Settings Considered

Tested narenas reduction, tcache_max, extent fit tuning, background
threads, and decay timer values. Only the decay timer configuration
improved steady-state RSS without wall time regression.
2026-02-26 23:47:47 -05:00
Jesse Zomer ac2ef1aaef 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
2026-02-26 16:21:10 -05:00
Jason Jean 191054d876 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>
2026-02-26 15:40:35 -05:00
Eric Baer b8b6ed8b85 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>
2026-02-26 15:20:15 -05:00
Jason Jean bdc61b5ad5 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
2026-02-26 13:13:34 -05:00
Jason Weinzierl 31dad4109b 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
2026-02-26 12:35:59 -05:00
omasakun c3643126ef 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
2026-02-26 11:45:51 -05:00
Anurag Agarwal dcfc2134d4 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>
2026-02-26 11:20:42 -05:00
Jack Hsu 77100fac5d 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
2026-02-26 10:42:51 -05:00
Leosvel Pérez Espinosa b1614d7504 feat(angular): add support for Angular v21.2 (#34592)
## Current Behavior

Nx doesn't support Angular v21.2.

## Expected Behavior

Nx should support Angular v21.2.
2026-02-26 10:23:53 -05:00
Caleb Ukle 0ae45cd445 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>
2026-02-26 17:56:54 +09:00
Jason Jean fcf4660389 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.
2026-02-25 23:02:58 -05:00
Louie Weng 221ea40462 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>
2026-02-25 21:50:07 +00:00
Leosvel Pérez Espinosa 12812dc994 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%.
2026-02-25 15:52:30 -05:00
Jack Hsu 4c3812f731 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
2026-02-25 15:49:44 -05:00
Leosvel Pérez Espinosa 098a830e5d 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.
2026-02-25 15:47:54 -05:00
Jason Jean f31e7a75be 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
2026-02-25 15:47:24 -05:00
Louie Weng 09c44a637a 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
2026-02-25 15:02:34 -05:00
Louie Weng dc81b8bbd6 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
2026-02-25 19:03:42 +00:00
Jack Hsu f7e46e33e9 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
2026-02-25 13:56:03 -05:00
Jason Jean 5d64f726d6 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.
2026-02-25 13:36:48 -05:00
Nikola Kalinov 1e1a8a7a40 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 #
2026-02-25 13:27:05 -05:00
Leosvel Pérez Espinosa 872b9c9045 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>
2026-02-25 12:39:17 -05:00
Jack Hsu 1e3f8e00f7 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
2026-02-25 12:27:22 -05:00
Philip Fulcher 919907cf0f docs(nx-dev): add foundations article (#34599) 2026-02-25 11:23:22 -06:00
Charlie Croom d5cd6a1a56 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>
2026-02-25 09:45:31 -05:00
Caleb Ukle 700c98fcaf 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)
2026-02-25 14:30:34 +00:00
Colum Ferry df9eb0bf10 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
2026-02-25 09:10:01 -05:00
MaxKless 4e55f9aa32 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>
2026-02-25 08:26:01 -05:00
Jack Hsu 127255aa96 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
2026-02-25 08:16:05 -05:00
Kai Gritun b46de60cd9 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.
2026-02-25 13:28:19 +01:00
Tomas Ptacek 736551590a 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
2026-02-25 09:55:15 +00:00
MaxKless e031d024ef chore(repo): update @nx/graph to 1.0.4 (#34558) 2026-02-25 18:27:42 +09:00
Jason Jean d042483a3f 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>
2026-02-24 22:50:08 -05:00
Berend de Boer 39f252df97 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>
2026-02-24 22:31:27 -05:00
Aude Planchamp 3f70561586 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>
2026-02-24 22:31:13 -05:00
Miguel b72a203ed7 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
2026-02-24 22:30:24 -05:00
Craigory Coppola 1ecf0fb6a7 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
2026-02-24 17:44:40 -05:00
Jason Jean c743313078 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
2026-02-24 17:36:31 -05:00
Jason Jean 1bbe936513 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)
2026-02-24 17:34:24 -05:00
Jack Hsu c966e20746 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                                                           │
└─────────────────┴─────────────────────────────────────────────────────────────────────────────────────────────────┘
```
2026-02-24 16:42:31 -05:00
Miroslav Jonaš f42976f852 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 #
2026-02-24 15:39:27 -05:00
Leosvel Pérez Espinosa 6d90572257 fix(core): show the correct status for stopped continuous tasks (#34226)
## Current Behavior

### 1. Continuous tasks missing from `postTasksExecution` hook

When running continuous tasks (e.g., `nx serve app`) and stopping them
with Ctrl+C, the `postTasksExecution` lifecycle hook does not include
them in `taskResults`. This breaks plugins that rely on post-run
statistics (e.g., uploading task stats to DataDog).

### 2. Confusing TUI status when sibling continuous task exits

When multiple continuous tasks run together and one exits unexpectedly,
its sibling is marked as "failed" even though it was intentionally
terminated/stopped by the task orchestrator.

## Expected Behavior

1. All tasks, including continuous ones, are included in `taskResults`
for the `postTasksExecution` hook
2. Continuous tasks that are intentionally stopped (because dependent
tasks completed or during graceful shutdown) report as `success` with
`Stopped` display status
3. Continuous tasks that exit unexpectedly (crash) report as `failure`
4. TUI summary shows correct status: success when all tasks completed
successfully, square icon for stopped tasks

## Related Issue(s)

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

Supersedes:

- https://github.com/nrwl/nx/pull/33562
- https://github.com/nrwl/nx/pull/34132
2026-02-24 13:48:52 -05:00
Rares Matei f84ec34cbd 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
2026-02-24 17:34:51 +00:00
Juri 566a370375 docs(core): move synthetic monorepos back to "How Nx Works" sidebar section 2026-02-24 18:02:29 +01:00
Juri Strumpflohner 4c1dd1e5ed 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>
2026-02-24 16:51:20 +01:00
Loëck Vézien 8f64e844c9 feat(core): add yarn berry catalog support (#34552)
## Current Behavior

The Nx catalog system (`catalog:` protocol) only supports pnpm
workspaces. Yarn Berry (v4+) introduced [catalog
support](https://yarnpkg.com/features/catalogs) in `.yarnrc.yml`, but Nx
does not recognize `catalog:` references in Yarn workspaces. This means
Yarn Berry users cannot benefit from Nx's catalog-aware dependency
resolution, validation, or version updating.

## Expected Behavior

Nx should support Yarn Berry's `catalog:` protocol, just like it does
for pnpm. With this PR:

- `catalog:` and `catalog:<name>` references in `package.json`
dependencies are correctly resolved against `.yarnrc.yml` definitions
for Yarn Berry workspaces
- Validation provides helpful error messages with suggestions (missing
catalog, missing package, duplicate default definitions)
- Catalog versions can be updated programmatically via
`updateCatalogVersions`
- The `CatalogManager` interface is generalized with
`getCatalogDefinitionFilePaths()` and `CatalogDefinitions` to support
multiple package managers cleanly

### Changes

- **`YarnCatalogManager`** — New manager that reads `catalog:` /
`catalogs:` from `.yarnrc.yml`, mirroring the pnpm implementation with
Yarn-specific config paths and error messages
- **`yarn-workspace.ts`** — Type definitions for Yarn's `.yarnrc.yml`
catalog structure (`YarnWorkspaceYaml`, `YarnCatalogEntry`)
- **`manager-factory.ts`** — Registers `YarnCatalogManager` for `yarn`
package manager
- **`manager.ts`** — Adds `getCatalogDefinitionFilePaths()` to the
`CatalogManager` interface; moves `formatCatalogError` here from
`types.ts` (runtime function doesn't belong with type-only exports)
- **`types.ts`** — Adds generic `CatalogDefinitions` interface so
consumers don't need to depend on package-manager-specific types
- **`pnpm-manager.ts`** — Implements the new
`getCatalogDefinitionFilePaths()` method; import cleanup
- **592-line test suite** covering parsing, resolution, validation
(named catalogs, default catalog, dual-definition errors, missing
catalogs/packages with suggestions), and `updateCatalogVersions`

### Context

I'm currently applying a patch on the compiled `@nx/devkit` package in
my Yarn Berry project to get catalog support while waiting for upstream
support:

<details>
<summary>Current workaround patch on <code>@nx/devkit</code></summary>

```diff
diff --git a/src/utils/catalog/manager-factory.js b/src/utils/catalog/manager-factory.js
index 6216749..d46e242 100644
--- a/src/utils/catalog/manager-factory.js
+++ b/src/utils/catalog/manager-factory.js
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
 exports.getCatalogManager = getCatalogManager;
 const devkit_exports_1 = require("nx/src/devkit-exports");
 const pnpm_manager_1 = require("./pnpm-manager");
+const yarn_manager_1 = require("./yarn-manager");
 /**
  * Factory function to get the appropriate catalog manager based on the package manager
  */
@@ -11,6 +12,8 @@ function getCatalogManager(workspaceRoot) {
     switch (packageManager) {
         case 'pnpm':
             return new pnpm_manager_1.PnpmCatalogManager();
+        case 'yarn':
+            return new yarn_manager_1.YarnCatalogManager();
         default:
             return null;
     }
diff --git a/src/utils/catalog/yarn-manager.js b/src/utils/catalog/yarn-manager.js
new file mode 100644
index 0000000..048fdec
--- /dev/null
+++ b/src/utils/catalog/yarn-manager.js
@@ -0,0 +1,102 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.YarnCatalogManager = void 0;
+const node_fs_1 = require("node:fs");
+const node_path_1 = require("node:path");
+const devkit_exports_1 = require("nx/src/devkit-exports");
+const devkit_internals_1 = require("nx/src/devkit-internals");
+class YarnCatalogManager {
+    constructor() {
+        this.name = 'yarn';
+        this.catalogProtocol = 'catalog:';
+    }
+    isCatalogReference(version) {
+        return version.startsWith(this.catalogProtocol);
+    }
+    parseCatalogReference(version) {
+        if (!this.isCatalogReference(version)) { return null; }
+        return { catalogName: undefined, isDefaultCatalog: true };
+    }
+    getCatalogDefinitions(treeOrRoot) {
+        if (typeof treeOrRoot === 'string') {
+            const p = (0, node_path_1.join)(treeOrRoot, '.yarnrc.yml');
+            if (!(0, node_fs_1.existsSync)(p)) { return null; }
+            return readYamlFileFromFs(p);
+        } else {
+            if (!treeOrRoot.exists('.yarnrc.yml')) { return null; }
+            return readYamlFileFromTree(treeOrRoot, '.yarnrc.yml');
+        }
+    }
+    resolveCatalogReference(treeOrRoot, packageName, version) {
+        if (!this.parseCatalogReference(version)) { return null; }
+        const config = this.getCatalogDefinitions(treeOrRoot);
+        if (!config || !config.catalog) { return null; }
+        return config.catalog[packageName] || null;
+    }
+    validateCatalogReference(treeOrRoot, packageName, version) {
+        if (!this.parseCatalogReference(version)) {
+            throw new Error(`Invalid catalog reference: "${version}"`);
+        }
+        const config = this.getCatalogDefinitions(treeOrRoot);
+        if (!config) { throw new Error('No .yarnrc.yml found'); }
+        if (!config.catalog) { throw new Error('No catalog in .yarnrc.yml'); }
+        if (!config.catalog[packageName]) {
+            throw new Error(`"${packageName}" not in .yarnrc.yml catalog`);
+        }
+    }
+    updateCatalogVersions() {}
+}
+exports.YarnCatalogManager = YarnCatalogManager;
+function readYamlFileFromFs(path) {
+    try { return (0, devkit_internals_1.readYamlFile)(path); }
+    catch (e) {
+        devkit_exports_1.output.warn({ title: 'Unable to parse .yarnrc.yml', bodyLines: [e.toString()] });
+        return null;
+    }
+}
+function readYamlFileFromTree(tree, path) {
+    const content = tree.read(path, 'utf-8');
+    const { load } = require('@zkochan/js-yaml');
+    try { return load(content, { filename: path }); }
+    catch (e) {
+        devkit_exports_1.output.warn({ title: 'Unable to parse .yarnrc.yml', bodyLines: [e.toString()] });
+        return null;
+    }
+}
```

</details>

This PR replaces that workaround with a proper TypeScript implementation
including full test coverage, named catalog support, helpful error
messages, and `updateCatalogVersions` support.

## Related Issue(s)

<!-- No existing issue found for Yarn Berry catalog support — this PR
introduces the feature -->
2026-02-24 10:34:40 -05:00
Jack Hsu 7f7bba633d 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
2026-02-24 08:31:57 -05:00
Colum Ferry 1a15ea183a 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
2026-02-24 12:51:54 +00:00
Juri Strumpflohner 8c0600225a 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>
2026-02-24 13:46:52 +01:00
MaxKless 832355081b 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>
2026-02-24 19:42:41 +09:00
MaxKless 1081c320ab 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
2026-02-24 10:34:41 +01:00
Samuel Briole bdeeb036fb 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>
2026-02-23 22:32:01 -05:00
Jack Hsu 4b1bf5f7ba 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>
2026-02-23 16:00:46 -05:00
Jack Hsu f935d9a7bf 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>
2026-02-23 15:47:41 -05:00
Jason Jean dd325d790a 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 -->
2026-02-23 12:28:58 -05:00
Jason Jean ed786fb12c 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.
2026-02-23 12:22:36 -05:00
Jason Jean cc5eeefde9 feat(core): add preferBatch executor option (#34293)
## Current Behavior

Batch mode is binary:
- `--batch` flag → batch ALL executors that support it
- No flag → batch NOTHING

This means users of gradle/maven must always remember to pass `--batch`
to get the performance benefits.

## Expected Behavior

Plugin authors can now set `preferBatch: true` in their executor config
to indicate batch mode should be used by default. Users can still
opt-out with `--no-batch`.

Three states:
- `--batch` → batch everything
- `--no-batch` → batch nothing  
- (not specified) → use each executor's `preferBatch` preference

| `--batch` flag | `preferBatch` | Result |
|----------------|---------------|--------|
| `true`         | any           | Batch  |
| `false`        | any           | No batch |
| not set        | `true`        | Batch  |
| not set        | `false`/undefined | No batch |

## Changes

- Added `preferBatch?: boolean` to `ExecutorJsonEntryConfig` and
`ExecutorConfig` interfaces
- Updated `--batch` default from `false` to `undefined` to allow
`preferBatch` to decide
- Modified batch scheduling logic to respect `preferBatch`
- Enabled `preferBatch: true` for gradle and maven executors
- Added 5 unit tests covering all `preferBatch` scenarios

## Related Issue(s)

<!-- Link any related issues here -->
2026-02-23 12:19:15 -05:00
Jason Jean cf53d15ae5 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>
2026-02-23 11:50:54 -05:00
Mathias Schopmans 7351e21150 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
2026-02-23 16:23:21 +00:00
MaxKless c5ab66152a feat(core): add AI agent mode to nx import (#34498)
## Current Behavior

`nx import` relies on interactive prompts (enquirer) and spinners (ora)
for user interaction. AI agents cannot parse this output or respond to
prompts, making `nx import` unusable in agent workflows.

## Expected Behavior

When `isAiAgent()` is true, `nx import` now:
- Skips all interactive prompts and spinners
- Emits NDJSON progress to stdout (`starting`, `cloning`, `filtering`,
`merging`, `detecting-plugins`, `complete`)
- Returns structured `needs_input` when required args are missing (all
at once to minimize round-trips)
- Returns structured `needs_input` for plugin selection when `--plugins`
flag is not provided
- Returns structured success/error results with hints and next steps
- Supports new `--plugins` flag (`skip`/`all`/comma-separated list)

Shared AI output types extracted from `init` into
`packages/nx/src/command-line/ai/ai-output.ts` for reuse across
commands.
2026-02-23 16:51:10 +01:00
MaxKless 1805301941 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>
2026-02-23 09:33:39 -05:00
MaxKless e8633e0299 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.
2026-02-23 21:45:51 +09:00
Colum Ferry 6bcaa46864 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
2026-02-23 11:50:43 +00:00
MaxKless d545472da8 feat(core): improve AX of configure-ai-agents with auto-detection (#34496)
## Current Behavior

When `configure-ai-agents` is invoked from within an AI agent (e.g.
Claude Code), it either shows an interactive multi-select prompt (which
the agent can't interact with) or requires `--agents` and
`--no-interactive` flags to work correctly. This makes the experience
awkward when AI agents call the command as part of workspace setup.

## Expected Behavior

When an AI agent is detected (via environment variables like
`CLAUDECODE`), the command now:

1. **Auto-configures the detected agent** if it's not yet configured,
partially configured, or outdated — no prompts needed
2. **Auto-updates any other outdated agents** alongside the detected one
3. **Reports non-configured agents** with a suggested `nx
configure-ai-agents --agents ...` command
4. **Reports up-to-date status** if the detected agent is already fully
configured

When `--agents` is explicitly passed, detection is ignored entirely
(existing behavior preserved). `--check` mode also works with detection
— it checks the detected agent plus all other configured agents.

Additionally:
- Strips AI agent detection env vars (`CLAUDECODE`, `CLAUDE_CODE`,
`OPENCODE`, `GEMINI_CLI`, etc.) from e2e subprocess environments to
prevent the test runner's environment from leaking into tests
- Fixes e2e tests to use `AGENTS.md` (not `GEMINI.md`) for gemini
assertions, matching what the gemini generator actually creates for
fresh installations

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-02-23 20:45:35 +09:00
Leosvel Pérez Espinosa 025db33a75 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.
2026-02-23 10:08:05 +00:00
Leosvel Pérez Espinosa 731db47fd7 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>
2026-02-23 09:42:07 +00:00
Copilot 4b6aea9f5e 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>
2026-02-23 18:35:55 +09:00
Altan Stalker 0568059fb8 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>
2026-02-20 18:24:33 -05:00
Craigory Coppola 3e5df300ab feat(core): add commands for debugging cache inputs / outputs (#34414)
## Current Behavior
There's not a great way to troubleshoot or test inputs and outputs
configurations on tasks.

## Expected Behavior
Adds `nx show target` to enable users to debug inputs and outputs. It
has flags `--inputs`, `--check-input`, `--outputs`, and `--check-output`
to list or test specific file patterns.

<img width="1077" height="198" alt="image"
src="https://github.com/user-attachments/assets/7ffd4502-1542-40e6-867c-37f70440a421"
/>

<img width="1077" height="105" alt="image"
src="https://github.com/user-attachments/assets/eb5b09e1-23fb-4710-9fb0-84f0c8e80c14"
/>

<img width="1077" height="538" alt="image"
src="https://github.com/user-attachments/assets/74c60668-285c-4195-ba77-6693a66e4897"
/>

<img width="1077" height="318" alt="image"
src="https://github.com/user-attachments/assets/ee228c43-98c2-441d-8b9d-277b38213e4d"
/>

<img width="1077" height="92" alt="image"
src="https://github.com/user-attachments/assets/8cca6553-4362-4662-b948-723abcc75671"
/>

<img width="1077" height="74" alt="image"
src="https://github.com/user-attachments/assets/6dc2188e-5dc5-4b5f-afd4-2a492a896e1d"
/>

---

<img width="492" height="430" alt="image"
src="https://github.com/user-attachments/assets/ae22bb2e-92c2-4c75-ad6f-b9cccda3def4"
/>

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: FrozenPandaz <jasonjean1993@gmail.com>
2026-02-20 17:35:50 -05:00
Jack Hsu 221ed882fa 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>
2026-02-20 19:56:58 +00:00
Craigory Coppola df8a2c43f4 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>
2026-02-20 13:49:21 -05:00
Jason Jean 391d23c65e 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
2026-02-20 12:17:20 -05:00
Jason Jean 092cea6073 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
2026-02-20 11:21:34 -05:00
Jack Hsu de2dc7ca13 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
2026-02-20 11:08:50 -05:00
Jason Jean 5236e02308 chore(maven): bump maven plugin version to 0.0.14 (#34505)
## Current Behavior

The Maven plugin is on version `0.0.13`.

## Expected Behavior

The Maven plugin is bumped to version `0.0.14`, with a migration
generated for Nx `22.6.0-beta.1`.
2026-02-19 18:27:14 -05:00
Altan Stalker 8e1d873edc 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
2026-02-19 22:41:35 +00:00
324 changed files with 19715 additions and 4523 deletions
+3
View File
@@ -1,3 +1,6 @@
[env]
JEMALLOC_SYS_WITH_MALLOC_CONF = "dirty_decay_ms:1000,muzzy_decay_ms:0"
[build]
target-dir = 'dist/target'
+4 -3
View File
@@ -31,7 +31,8 @@ jobs:
NX_CLOUD_USE_NEW_TASK_APIS: 'true'
NX_CLOUD_USE_NEW_STREAM_OUTPUT: 'true'
NX_CLOUD_EXPERIMENTAL_POLLING: 'true'
NX_CLOUD_CONTINUOUS_ASSIGNMENT: 'true'
NX_CLOUD_CONTINUOUS_ASSIGNMENT: 'false'
NX_CLOUD_VERBOSE_LOGGING: 'true'
steps:
- name: Checkout
@@ -77,7 +78,7 @@ jobs:
pnpm playwright install --with-deps
- name: Nx Report
run:
run:
pnpm nx report
- name: Run Checks/Lint/Test/Build
@@ -96,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
+13 -2
View File
@@ -174,7 +174,7 @@ jobs:
bash -c "
set -e
echo 'https://dl-cdn.alpinelinux.org/alpine/edge/community' >> /etc/apk/repositories
apk add --no-cache curl xz openjdk21
apk add --no-cache curl xz openjdk21 build-base lld
# Set up Java 21
export JAVA_HOME=/usr/lib/jvm/java-21-openjdk
@@ -194,6 +194,10 @@ jobs:
npm i -g pnpm@${PNPM_VERSION} --force
pnpm --version
# Help clang find GCC runtime (crtbeginS.o, libgcc) and use lld for jemalloc build
GCC_DIR=\$(dirname \$(find /usr/lib/gcc -name crtbeginS.o | head -1))
export CFLAGS=\"\${CFLAGS} -fuse-ld=lld --gcc-install-dir=\${GCC_DIR}\"
# Install deps and run native build
pnpm install --frozen-lockfile
rustup target add x86_64-unknown-linux-musl
@@ -230,6 +234,9 @@ jobs:
node --version
npm --version
# Help clang find GCC runtime (crtbeginS.o, libgcc) and use lld for jemalloc build
export CFLAGS="${CFLAGS} -fuse-ld=lld --gcc-toolchain=/usr/aarch64-unknown-linux-gnu"
npm i -g pnpm@${PNPM_VERSION} --force
pnpm --version
@@ -260,7 +267,7 @@ jobs:
bash -c "
set -e
echo 'https://dl-cdn.alpinelinux.org/alpine/edge/community' >> /etc/apk/repositories
apk add --no-cache curl xz openjdk21
apk add --no-cache curl xz openjdk21 build-base lld
# Set up Java 21
export JAVA_HOME=/usr/lib/jvm/java-21-openjdk
@@ -280,6 +287,10 @@ jobs:
npm i -g pnpm@${PNPM_VERSION} --force
pnpm --version
# Help clang find GCC runtime (crtbeginS.o, libgcc) and use lld for jemalloc build
GCC_DIR=\$(dirname \$(find /aarch64-linux-musl-cross/lib/gcc -name crtbeginS.o | head -1))
export CFLAGS=\"\${CFLAGS} -fuse-ld=lld --gcc-install-dir=\${GCC_DIR}\"
# Install deps and run native build
pnpm install --frozen-lockfile
rustup target add aarch64-unknown-linux-musl
+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/
Generated
+21
View File
@@ -2214,6 +2214,7 @@ dependencies = [
"tempfile",
"terminal-colorsaurus",
"thiserror 1.0.69",
"tikv-jemallocator",
"tokio",
"tokio-util",
"tracing",
@@ -3832,6 +3833,26 @@ dependencies = [
"zune-jpeg",
]
[[package]]
name = "tikv-jemalloc-sys"
version = "0.6.1+5.3.0-1-ge13ca993e8ccb9ba9847cc330696e02839f328f7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd8aa5b2ab86a2cefa406d889139c162cbb230092f7d1d7cbc1716405d852a3b"
dependencies = [
"cc",
"libc",
]
[[package]]
name = "tikv-jemallocator"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0359b4327f954e0567e69fb191cf1436617748813819c94b8cd4a431422d053a"
dependencies = [
"libc",
"tikv-jemalloc-sys",
]
[[package]]
name = "time"
version = "0.3.44"
+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. |
@@ -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);
});
});
+13 -9
View File
@@ -93,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',
},
],
},
{
@@ -100,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',
@@ -394,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' },
{
@@ -891,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',
@@ -900,10 +912,6 @@ const knowledgeBaseGroups: SidebarItems = [
label: 'TypeScript Project Linking',
link: 'concepts/typescript-project-linking',
},
{
label: 'Maintain TypeScript Monorepos',
link: 'features/maintain-typescript-monorepos',
},
],
},
{
@@ -1002,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' },
@@ -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

@@ -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"
{
@@ -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
@@ -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' />
@@ -9,7 +9,7 @@ filter: 'type:Features'
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.
Nx's AI integration gives assistants accurate, real-time information about your workspace, projects, and available commandsmaking them smarter when working in an Nx monorepo and more autonomous when iterating on CI failures.
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
@@ -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.
@@ -16,7 +16,7 @@ Nx is a build system for monorepos. It helps you **develop faster** and **keep C
Monorepos have many advantages and are especially powerful for AI-assisted development. But as teams and codebases grow, monorepos are hard to scale:
- **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.
- **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.
@@ -40,7 +40,7 @@ nx run-many -t build test # Run across all projects
{% callout type="deepdive" title="How does Nx run tasks?" %}
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`:
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
@@ -53,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
@@ -72,7 +72,7 @@ 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/plugin-registry), optimizing your CI via [task distribution](/docs/features/ci-features/distribute-task-execution), and many more powerful capabilities as your needs grow.
@@ -80,7 +80,7 @@ From there, you can gradually enhance your setup by adding features like [task c
## Start Small, Grow as Needed
Nx is modular. Start with just the CLI and add capabilities as your needs grow.
Nx is modular. Start with the CLI and add capabilities as your needs grow.
| Component | What It Does |
| ---------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -115,7 +115,7 @@ Nx can also connect multiple repositories into a synthetic monorepo, letting you
{% linkcard title="Concepts" description="Improve your understanding of how Nx works under the hood." href="/docs/concepts" /%}
{% linkcard title="Features" description="Discover all the powerful features that Nx provides to streamline your workflow." href="/docs/features" /%}
{% 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" /%}
@@ -9,7 +9,7 @@ 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" /%}
Nx is designed for incremental adoption. Start with just 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.
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.
Add Nx to any existing project with a single command:
@@ -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`).
@@ -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:
@@ -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.
@@ -464,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
@@ -501,7 +515,7 @@ Example patterns and their results:
"requireSemver": true,
"strictPreid": true,
"preferDockerVersion": false,
"checkAllBranchesWhen": "main",
"checkAllBranchesWhen": ["main", "release/*"],
},
},
}
@@ -518,7 +532,7 @@ Example patterns and their results:
"releaseTagPatternRequireSemver": true,
"releaseTagPatternStrictPreid": true,
"releaseTagPatternPreferDockerVersion": false,
"releaseTagPatternCheckAllBranchesWhen": "main",
"releaseTagPatternCheckAllBranchesWhen": ["main", "release/*"],
},
}
```
@@ -20,6 +20,7 @@ We provide a recommended version, and it is usually the latest minor version of
| Angular Version | **Nx Version _(recommended)_** | Nx Version _(range)_ |
| --------------- | ------------------------------ | ---------------------------------------- |
| ~21.2.0 | **latest** | >=22.6.0 <=latest |
| ~21.1.0 | **latest** | >=22.4.0 <=latest |
| ~21.0.0 | **latest** | >=22.3.0 <=latest |
| ~20.3.0 | **latest** | >=21.6.1 <=latest |
@@ -1,11 +1,26 @@
---
title: 'createConfig - @nx/angular-rsbuild'
description: 'API Reference for createConfig from @nx/angular-rsbuild'
title: 'Angular Rsbuild Plugin for Nx'
description: 'Use Rsbuild as the build tool for Angular applications in your Nx workspace with the @nx/angular-rsbuild plugin.'
sidebar:
label: 'Create Config'
label: 'Introduction'
filter: 'type:References'
---
The `@nx/angular-rsbuild` package provides configuration utilities for building Angular applications with [Rsbuild](https://rsbuild.dev). Rsbuild is built on top of Rspack and offers a streamlined development experience with fast builds and hot module replacement.
## Requirements
The `@nx/angular-rsbuild` plugin supports the following package versions.
| Package | Supported Versions |
| --------------- | ----------------------------------------------------------------------------------------- |
| `@rsbuild/core` | ^1.1.0 |
| `@angular/core` | See [Angular version matrix](/docs/technologies/angular/guides/angular-nx-version-matrix) |
[Nx generators](/docs/features/generate-code) install the latest supported versions automatically when scaffolding new projects.
## Usage
```shell
import { createConfig } from '@nx/angular-rsbuild';
```
@@ -1,5 +1,5 @@
---
title: 'Introduction - Angular Rspack Compiler'
title: 'Angular Rspack Compiler'
description: 'Compilation utilities for Angular with Rspack and Rsbuild.'
sidebar:
label: 'Introduction'
@@ -1,18 +1,29 @@
---
title: 'Introduction - Angular Rspack'
title: 'Angular Rspack Plugin for Nx'
description: 'Learn how Rspack can help you speed up your Angular applications.'
sidebar:
label: 'Introduction'
filter: 'type:References'
---
Angular's compilation has always been a black box hidden behind layers of abstraction and configuration, exposed via the Angular Builders from the Angular CLI packages.
## Requirements
The `@angular-rspack/nx` plugin supports the following package versions.
| Package | Supported Versions |
| --------------- | ----------------------------------------------------------------------------------------- |
| `@rspack/core` | >=1.3.5 <1.7.0 |
| `@angular/core` | See [Angular version matrix](/docs/technologies/angular/guides/angular-nx-version-matrix) |
[Nx generators](/docs/features/generate-code) install the latest supported versions automatically when scaffolding new projects.
Angular compilation has always been a black box hidden behind layers of abstraction and configuration, exposed via the Angular Builders from the Angular CLI packages.
Originally, the underlying tool that bundled the Angular application was [Webpack](https://webpack.js.org). This was great as teams were able to extend their builds by leveraging the vast Webpack ecosystem and plugins that are available.
Over time, it became clear that the inherit slowness with Webpack build speeds was becoming more and more of an issue for Angular developers.
The Angular Team decided to address this build speed issue by building out a new build pipeline that leveraged [Esbuild](https://esbuild.github.io/).
The Angular Team decided to address this build speed issue by building out a new build pipeline that used [Esbuild](https://esbuild.github.io/).
This succeeded in reducing the build times for Angular applications, however, it made one crucial mistake. It left the existing Angular applications that relied on the Webpack ecosystem behind, with either a difficult migration path or none at all.
@@ -20,15 +31,15 @@ This succeeded in reducing the build times for Angular applications, however, it
## Rspack
The solution to this problem was to create a new build pipeline that would be able to leverage the existing Webpack ecosystem and plugins, while also providing faster builds for Angular applications.
The solution to this problem was to create a new build pipeline that could use the existing Webpack ecosystem and plugins while also providing faster builds for Angular applications.
This is where [Rspack](https://rspack.dev) come into play.
Rspack is a high performance JavaScript bundler written in Rust. It offers strong compatibility with the Webpack ecosystem, allowing for almost seamless replacement of webpack, and provides lightning fast build speeds.
Rspack is a high performance JavaScript bundler written in Rust. It offers strong compatibility with the Webpack ecosystem, and can serve as a near drop-in replacement for webpack with significantly faster build speeds.
Because it supports the existing Webpack ecosystem, it provides an answer to teams that maintain Angular applications using Webpack and want to migrate to a faster build pipeline.
This makes it a great solution for teams that want to migrate to a faster build pipeline, but still want the ability to easily extend their builds and use [Module Federation](https://module-federation.io).
This makes it a great solution for teams that want to migrate to a faster build pipeline, but still want the ability to extend their builds and use [Module Federation](https://module-federation.io).
{% aside type="caution" title="Angular Rspack Status" %}
@@ -12,7 +12,17 @@ filter: 'type:References'
The `@nx/angular` plugin adds [generators](#local-development), Angular CLI builder integration (executors) and migrations so you can run Angular tasks through Nx. With Nx, each project has its own configuration instead of a single `angular.json` file, making it more scalable for monorepos.
You can use Angular with Nx without the plugin and still get [task caching](/docs/features/cache-task-results), [task orchestration](/docs/features/run-tasks), and the [project graph](/docs/features/explore-graph).
See the [Nx and Angular versions matrix](/docs/technologies/angular/guides/angular-nx-version-matrix) to know which Nx version supports a given Angular version.
## Requirements
The `@nx/angular` plugin supports the following package versions.
| Package | Supported Versions |
| --------------- | ------------------ |
| `@angular/core` | >= 19.0.0 < 22.0.0 |
[Nx generators](/docs/features/generate-code) install the latest supported versions automatically when scaffolding new projects.
For older Nx versions, see the full [Nx and Angular versions matrix](/docs/technologies/angular/guides/angular-nx-version-matrix).
## Setup
@@ -1,5 +1,5 @@
---
title: Overview of the Nx Docker Plugin
title: Docker Plugin for Nx
description: The Nx Plugin for Docker contains executors and utilities for building and publishing docker images within an Nx workspace.
keywords: [docker]
sidebar:
@@ -1,6 +1,6 @@
---
title: Overview of the Nx esbuild Plugin
description: The Nx Plugin for esbuild contains executors and generators that support building applications using esbuild. This page also explains how to configure esbuild on your Nx workspace.
title: esbuild Plugin for Nx
description: The Nx Plugin for esbuild contains executors and generators that support building applications using esbuild, including setup and configuration for your Nx workspace.
sidebar:
label: Introduction
filter: 'type:References'
@@ -8,6 +8,16 @@ filter: 'type:References'
The Nx Plugin for [esbuild](https://esbuild.github.io/api/), an extremely fast JavaScript bundler.
## Requirements
The `@nx/esbuild` plugin supports the following package versions.
| Package | Supported Versions |
| --------- | ------------------ |
| `esbuild` | >=0.19.2 <1.0.0 |
[Nx generators](/docs/features/generate-code) install the latest supported versions automatically when scaffolding new projects.
Why should you use this plugin?
- _Fast_ builds using esbuild.
@@ -1,5 +1,5 @@
---
title: Overview of the Nx Rollup Plugin
title: Rollup Plugin for Nx
description: The Nx Plugin for Rollup contains executors and generators that support building applications using Rollup.
sidebar:
label: Introduction
@@ -8,6 +8,16 @@ filter: 'type:References'
The Nx Plugin for Rollup contains executors and generators that support building applications using Rollup.
## Requirements
The `@nx/rollup` plugin supports the following package versions.
| Package | Supported Versions |
| -------- | ------------------ |
| `rollup` | ^4.14.0 |
[Nx generators](/docs/features/generate-code) install the latest supported versions automatically when scaffolding new projects.
## Setting Up @nx/rollup
### Installation
@@ -1,5 +1,5 @@
---
title: Overview of the Nx Rsbuild Plugin
title: Rsbuild Plugin for Nx
description: The Nx Plugin for Rsbuild contains executors and generators that support building applications using Rsbuild.
sidebar:
label: Introduction
@@ -8,6 +8,16 @@ filter: 'type:References'
The Nx Plugin for Rsbuild contains executors and generators that support building applications using Rsbuild.
## Requirements
The `@nx/rsbuild` plugin supports the following package versions.
| Package | Supported Versions |
| --------------- | ------------------ |
| `@rsbuild/core` | ^1.1.0 |
[Nx generators](/docs/features/generate-code) install the latest supported versions automatically when scaffolding new projects.
## Setting Up @nx/rsbuild
### Installation
@@ -1,5 +1,5 @@
---
title: Overview of the Nx Rspack Plugin
title: Rspack Plugin for Nx
description: The Nx Plugin for Rspack contains executors, generators, and utilities for managing Rspack projects in an Nx Workspace.
sidebar:
label: Introduction
@@ -8,6 +8,16 @@ filter: 'type:References'
The Nx Plugin for Rspack contains executors, generators, and utilities for managing Rspack projects in an Nx Workspace.
## Requirements
The `@nx/rspack` plugin supports the following package versions.
| Package | Supported Versions |
| -------------- | ------------------ |
| `@rspack/core` | ^1.6.0 |
[Nx generators](/docs/features/generate-code) install the latest supported versions automatically when scaffolding new projects.
## Setting Up @nx/rspack
### Installation
@@ -1,5 +1,5 @@
---
title: Overview of the Nx Vite Plugin
title: Vite Plugin for Nx
description: Use Vite with Nx for inferred dev/build tasks, generators, and CI-friendly workflows.
sidebar:
label: Introduction
@@ -16,6 +16,16 @@ Starting with Nx v22, Vitest support has moved to the dedicated [`@nx/vitest` pl
You can use Vite with Nx without the plugin and still get [task caching](/docs/features/cache-task-results), [task orchestration](/docs/features/run-tasks), and the [project graph](/docs/features/explore-graph).
## Requirements
The `@nx/vite` plugin supports the following package versions.
| Package | Supported Versions |
| ------- | ------------------------------ |
| `vite` | ^5.0.0 \|\| ^6.0.0 \|\| ^7.0.0 |
[Nx generators](/docs/features/generate-code) install the latest supported versions automatically when scaffolding new projects.
## Setup
### Add to an existing workspace
@@ -1,5 +1,5 @@
---
title: Overview of the Nx Webpack Plugin
title: Webpack Plugin for Nx
description: The Nx Plugin for Webpack contains executors and generators that support building applications using Webpack.
sidebar:
label: Introduction
@@ -10,7 +10,17 @@ The Nx plugin for [webpack](https://webpack.js.org/).
[Webpack](https://webpack.js.org/) is a static module bundler for modern JavaScript applications. The `@nx/webpack` plugin provides executors that allow you to build and serve your projects using webpack, plus an executor for SSR.
Nx now allows you to [customize your webpack configuration](/docs/technologies/build-tools/webpack/guides/webpack-config-setup) for your projects. And we also offer [a number of webpack plugins](/docs/technologies/build-tools/webpack/guides/webpack-plugins) for supporting Nx and other frameworks.
You can [customize your webpack configuration](/docs/technologies/build-tools/webpack/guides/webpack-config-setup) for your projects. Nx also provides [a number of webpack plugins](/docs/technologies/build-tools/webpack/guides/webpack-plugins) for supporting Nx and other frameworks.
## Requirements
The `@nx/webpack` plugin supports the following package versions.
| Package | Supported Versions |
| --------- | ------------------ |
| `webpack` | >=5.0.0 |
[Nx generators](/docs/features/generate-code) install the latest supported versions automatically when scaffolding new projects.
## Setting up a new Nx workspace with Webpack
@@ -1,5 +1,5 @@
---
title: Overview of the Nx Plugin for .NET
title: .NET Plugin for Nx
description: This plugin allows .NET projects to be run through Nx.
sidebar:
label: 'Introduction'
@@ -6,7 +6,17 @@ sidebar:
filter: 'type:References'
---
The ESLint plugin integrates [ESLint](https://eslint.org/) with Nx. It allows you to run ESLint through Nx with caching enabled. It also includes code generators to help you set up ESLint in your workspace.
The ESLint plugin integrates [ESLint](https://eslint.org/) with Nx. Run ESLint through Nx with caching enabled, and use the included code generators to set up ESLint in your workspace.
## Requirements
The `@nx/eslint` plugin supports the following package versions.
| Package | Supported Versions |
| -------- | ------------------ |
| `eslint` | ^8.0.0 \|\| ^9.0.0 |
[Nx generators](/docs/features/generate-code) install the latest supported versions automatically when scaffolding new projects.
## Setting Up @nx/eslint
@@ -1,5 +1,5 @@
---
title: Overview of the Nx Plugin for Gradle
title: Gradle Plugin for Nx
description: Run Gradle tasks through Nx with caching, graph insights, and CI optimization.
sidebar:
label: 'Introduction'
@@ -12,12 +12,17 @@ The `@nx/gradle` plugin registers Gradle projects in the Nx graph so you can [se
You can use Gradle with Nx without the plugin and still get [task caching](/docs/features/cache-task-results), [task orchestration](/docs/features/run-tasks), and the [project graph](/docs/features/explore-graph).
## Requirements
| Dependency | Supported Versions |
| ---------- | ------------------ |
| Java | >= 17 |
| Gradle | >= 8.0 |
Using older Java versions is unsupported and may lead to issues. If you need support for an older version, please create an issue on [GitHub](https://github.com/nrwl/nx).
## Setup
### Prerequisites
- Java 17 or newer
### Install Nx
Install Nx with your preferred package manager:
@@ -10,9 +10,11 @@ Nx provides powerful tooling for Java projects, supporting both Gradle and Maven
## Requirements
{% aside type="note" title="Java Compatibility" %}
Both Nx plugins require Java 17 or newer. Using older Java versions is unsupported and may lead to issues. If you need support for an older version, please create an issue on [Github](https://github.com/nrwl/nx)!
{% /aside %}
| Dependency | Supported Versions |
| ---------- | ------------------ |
| Java | >= 17 |
Using older Java versions is unsupported and may lead to issues. If you need support for an older version, please create an issue on [GitHub](https://github.com/nrwl/nx).
## Quick Start
@@ -1,5 +1,5 @@
---
title: Overview of the Nx Plugin for Maven
title: Maven Plugin for Nx
description: This plugin allows Maven tasks to be run through Nx.
sidebar:
label: 'Introduction'
@@ -16,13 +16,17 @@ The `@nx/maven` plugin registers Maven modules as Nx projects so you can [set up
You can use Maven with Nx without the plugin and still get [task caching](/docs/features/cache-task-results), [task orchestration](/docs/features/run-tasks), and the [project graph](/docs/features/explore-graph).
## Requirements
| Dependency | Supported Versions |
| ---------- | ------------------ |
| Java | >= 17 |
| Maven | >= 3.6.0 |
Using older Java versions is unsupported and may lead to issues. If you need support for an older version, please create an issue on [GitHub](https://github.com/nrwl/nx).
## Setup
### Prerequisites
- **Java 17 or newer**
- **Maven 3.6.0 or newer**
### Install Nx
You can install Nx globally. Depending on your package manager, use one of the following commands:
@@ -1,12 +1,23 @@
---
title: NxModuleFederationPlugin
title: Module Federation Plugin for Nx
description: Details about the NxModuleFederationPlugin
sidebar:
label: Introduction
filter: 'type:References'
---
The `NxModuleFederationPlugin` is a [Rspack](https://rspack.dev) plugin that handles module federation in Nx Workspaces. It aims to provide the same Developer Experience(DX) that you would normally receive from using Nx's `withModuleFederation` function.
The `NxModuleFederationPlugin` is a [Rspack](https://rspack.dev) plugin that handles module federation in Nx Workspaces. It aims to provide the same Developer Experience (DX) that you would normally get from using the Nx `withModuleFederation` function.
## Requirements
The `@nx/module-federation` plugin supports the following package versions.
| Package | Supported Versions |
| -------------- | ------------------ |
| `webpack` | ^5.0.0 |
| `@rspack/core` | ^1.6.0 |
[Nx generators](/docs/features/generate-code) install the latest supported versions automatically when scaffolding new projects.
## Usage
@@ -1,31 +1,37 @@
---
title: Bundling Node.js Applications and Libraries
description: Learn how to configure bundling for Node.js applications and libraries in an Nx monorepo using Webpack, esbuild, and Vite.
title: Bundling Projects for Deployment
description: Bundle your Node.js application into a single file with no node_modules needed. Deploy without a package.json install step.
sidebar:
label: Understand Bundling with Node
label: Bundling for Deployment
filter: 'type:Guides'
---
When building Node.js projects, you have two main approaches to distribute your projects final artifact from the monorepo, **bundled** or **not bundled**. Depending on your deployment strategy and tooling preferences, one approach may be more suitable than the other.
Bundling compiles your code and all its dependencies into a single file (e.g. `main.js`).
The output is self-contained, so you don't need `node_modules` or an install step at deploy time.
## Bundled vs Non-Bundled Builds
If your app has native dependencies or you want Docker layer caching for `node_modules`,
see [pruning projects for deployment](/docs/technologies/node/guides/deploying-node-projects) instead.
## When to bundle instead of prune
| Approach | Best for | Trade-off |
| ----------------------------------------------------------------- | --------------------------------------- | --------------------------------------------- |
| Bundling | Serverless functions, simple APIs | Single file output, no `node_modules` needed |
| [Pruning](/docs/technologies/node/guides/deploying-node-projects) | Docker deployments, native dependencies | Keeps `node_modules` but only production deps |
Use bundling when:
- Your app has no native dependencies that require OS-level installation
- You want a single deployable artifact with no install step
- You're targeting serverless platforms or lightweight containers
**Bundled builds** compile your code and all its dependencies into a single file, e.g. `main.js` This approach:
{% aside type="note" title="Lazy loaded chunks" %}
If you're using lazy loaded chunks in your node application, bundling will produce more than a single file. Instead, you'll have a file per chunks entrypoint file. You'll want to make sure all the files are handled correctly for your deployment needs.
If you use lazy loaded chunks, bundling produces more than a single file.
You'll have one file per chunk entrypoint.
Make sure all files are handled correctly for your deployment needs.
{% /aside %}
- Produces a self-contained artifact that doesn't require `node_modules`
- Simplifies deployment since you only need to copy a single file
- Works well for serverless functions and containerized applications
**Non-bundled builds** preserve your module structure and require `node_modules` at runtime. This approach:
- Requires installing dependencies before running
- Maintains separate files for each module
- Can improve container rebuilds speeds when paired with Docker Layer Caching
## Bundling Node.js Applications
## Bundling Node.js applications
{% tabs syncKey="bundler" %}
@@ -130,18 +136,22 @@ nx build my-app
# Deploy dist/my-app/main.js - no node_modules needed
```
## When NOT to Bundle
## When not to bundle
If you're publishing a library package to npm, avoid bundling dependencies. Instead, declare them in `package.json` so package managers can handle versioning and deduplication.
If you're publishing a library package to npm, avoid bundling dependencies.
Declare them in `package.json` so package managers can handle versioning and deduplication.
For Docker based deployments, non-bundled builds can improve build times through layer caching. When dependencies don't change, Docker reuses the cached `node_modules` layer, only rebuilding your application code.
For Docker-based deployments, non-bundled builds can improve build times through layer caching.
When dependencies don't change, Docker reuses the cached `node_modules` layer and only rebuilds your application code.
Instead of running `build`, use the `prune` target which prepares your application for deployment with its dependencies:
Instead of running `build`, use the `prune` target to prepare your application for deployment with its dependencies:
```shell
nx prune my-app
```
For the full setup, see [pruning projects for deployment](/docs/technologies/node/guides/deploying-node-projects).
This creates a deployment-ready structure:
```text
@@ -159,11 +169,12 @@ WORKDIR /app
CMD ["node", "main.js"]
```
## Bundling Libraries
## Bundling libraries
Nx recommends publishing workspace dependencies as separate packages rather than bundling them into a single library. This approach provides better versioning control and allows consumers to manage their own dependency trees.
Publish workspace dependencies as separate packages rather than bundling them into a single library.
This gives better versioning control and lets consumers manage their own dependency trees.
However, bundling workspace libraries could make sense when:
Bundling workspace libraries makes sense when:
- The library contains only types that should be inlined
- You want to distribute an internal library as part of your package
@@ -245,9 +256,9 @@ See `rollupOptions` from [vite documentation for more information](https://vite.
{% /tabs %}
## Managing Workspace Dependencies
## Managing workspace dependencies
When building libraries that consume other workspace libraries, always define the dependency relationship in `package.json`:
When building libraries that consume other workspace libraries, define the dependency relationship in `package.json`:
```json
// libs/my-lib/package.json
@@ -266,7 +277,7 @@ The `workspace:*` syntax:
This ensures your library correctly declares its dependencies regardless of whether they're bundled.
## Quick Reference
## Quick reference
| Scenario | Tool | Key Settings |
| --------------------------------------- | ------- | ------------------------------------------------------------ |
@@ -0,0 +1,296 @@
---
title: Pruning Projects for Deployment
description: Generate a pruned package.json and lockfile so Docker installs only production dependencies. Replaces the deprecated generatePackageJson option in Nx 20+.
sidebar:
label: Pruning for Deployment
filter: 'type:Guides'
---
When deploying Node.js applications to containers, you typically need only production dependencies, not your entire workspace `node_modules`.
Pruning generates a standalone `package.json`, a pruned lockfile, and copies any workspace libraries your app depends on.
The result is everything you need to run `npm ci` inside a Docker image with only the packages your application uses.
To bundle your app into a single file instead (no `node_modules` needed),
see [Bundling projects for deployment](/docs/technologies/node/guides/bundling-node-projects).
## When to prune instead of bundle
| Approach | Best for | Trade-off |
| ----------------------------------------------------------------- | --------------------------------------- | --------------------------------------------- |
| [Bundling](/docs/technologies/node/guides/bundling-node-projects) | Serverless functions, simple APIs | Single file output, no `node_modules` needed |
| Pruning | Docker deployments, native dependencies | Keeps `node_modules` but only production deps |
Use pruning when:
- Your app has native dependencies (e.g. `bcrypt`, `sharp`) that can't be bundled
- You want Docker layer caching, where dependency layers rebuild only when `package.json` changes
- You consume workspace libraries as packages rather than bundling them
{% aside type="tip" %}
New Node applications include prune targets by default.
Pass `--docker` to also generate an example Dockerfile: `nx g @nx/node:app --docker`.
{% /aside %}
## How pruning works
Pruning uses four Nx targets that run in sequence:
1. `build` compiles your application (esbuild, webpack, tsc, etc.).
1. `prune-lockfile` (`@nx/js:prune-lockfile`) reads your project `package.json`, generates a minimal `package.json`, and creates a pruned lockfile containing only production dependencies.
1. `copy-workspace-modules` (`@nx/js:copy-workspace-modules`) copies workspace libraries referenced via `workspace:*` into a `workspace_modules/` directory and rewrites their dependency references to `file:` paths.
1. `prune` (`nx:noop`) depends on both `prune-lockfile` and `copy-workspace-modules`, giving you a single command to run.
After running `nx prune my-app`, the build output directory contains:
```text
apps/my-app/dist/
├── main.js # Compiled application
├── package.json # Pruned production dependencies
├── package-lock.json # Pruned lockfile (or yarn.lock / pnpm-lock.yaml)
└── workspace_modules/ # Only present if you have workspace deps
└── @my-org/
└── my-lib/
├── package.json
└── ...
```
## Set up prune targets
Add the following targets to your project's `package.json` or `project.json`:
{% tabs syncKey="config" %}
{% tabitem label="package.json" %}
```json
// apps/my-app/package.json
{
"name": "@my-org/my-app",
"nx": {
"targets": {
"prune-lockfile": {
"dependsOn": ["build"],
"cache": true,
"executor": "@nx/js:prune-lockfile",
"outputs": [
"{workspaceRoot}/apps/my-app/dist/package.json",
"{workspaceRoot}/apps/my-app/dist/package-lock.json"
],
"options": {
"buildTarget": "build"
}
},
"copy-workspace-modules": {
"dependsOn": ["build"],
"cache": true,
"outputs": ["{workspaceRoot}/apps/my-app/dist/workspace_modules"],
"executor": "@nx/js:copy-workspace-modules",
"options": {
"buildTarget": "build"
}
},
"prune": {
"dependsOn": ["prune-lockfile", "copy-workspace-modules"],
"executor": "nx:noop"
}
}
}
}
```
{% /tabitem %}
{% tabitem label="project.json" %}
```json
// apps/my-app/project.json
{
"name": "@my-org/my-app",
"targets": {
"prune-lockfile": {
"dependsOn": ["build"],
"cache": true,
"executor": "@nx/js:prune-lockfile",
"outputs": [
"{workspaceRoot}/apps/my-app/dist/package.json",
"{workspaceRoot}/apps/my-app/dist/package-lock.json"
],
"options": {
"buildTarget": "build"
}
},
"copy-workspace-modules": {
"dependsOn": ["build"],
"cache": true,
"outputs": ["{workspaceRoot}/apps/my-app/dist/workspace_modules"],
"executor": "@nx/js:copy-workspace-modules",
"options": {
"buildTarget": "build"
}
},
"prune": {
"dependsOn": ["prune-lockfile", "copy-workspace-modules"],
"executor": "nx:noop"
}
}
}
```
{% /tabitem %}
{% /tabs %}
Replace `package-lock.json` in the `outputs` array with `yarn.lock` or `pnpm-lock.yaml` if needed.
Then run:
```shell
nx prune my-app
```
Both `prune-lockfile` and `copy-workspace-modules` set `cache: true`,
so subsequent runs are instant when nothing changes.
## Use pruned output in Docker
The generated Dockerfile copies the build output and runs `npm install`:
```dockerfile
# apps/my-app/Dockerfile
FROM docker.io/node:lts-alpine
ENV HOST=0.0.0.0
ENV PORT=3000
WORKDIR /app
COPY dist .
# You can remove this install step if you build with `--bundle` option.
# The bundled output will include external dependencies.
RUN npm --omit=dev -f install
CMD ["node", "main.js"]
```
The `COPY dist .` line works because the Dockerfile lives inside the project directory (`apps/my-app/`),
and the build output goes to `apps/my-app/dist/`.
The pruned `package.json`, lockfile, and `workspace_modules/` are all inside `dist/`.
Build and run:
```shell
# Build the app and prune dependencies
nx prune my-app
# Build the Docker image
npx nx docker:build my-app
# Run the container
nx docker:run my-app -p 3000:3000
```
## Migrate from `generatePackageJson`
If you're upgrading to Nx 20+ with TS Solution Setup (the default for new workspaces),
the `generatePackageJson` option is no longer supported.
You'll see this error:
{% aside type="caution" title="Error: generatePackageJson not supported" %}
`Setting 'generatePackageJson: true' is not supported with the current TypeScript setup. Update the 'package.json' file at the project root as needed and unset the 'generatePackageJson' option.`
{% /aside %}
Follow these steps to migrate to the prune workflow:
### Step 1: Move dependencies to your project package.json
With TS Solution Setup, each project has its own `package.json`.
List all runtime dependencies there:
```json
// apps/my-app/package.json
{
"name": "@my-org/my-app",
"dependencies": {
"express": "^4.18.0",
"@my-org/shared-utils": "workspace:*"
}
}
```
Use the `workspace:*` protocol for workspace libraries.
### Step 2: Remove `generatePackageJson` from your build configuration
{% tabs syncKey="bundler" %}
{% tabitem label="esbuild" %}
Remove `generatePackageJson` from your esbuild target options:
```json
// apps/my-app/package.json
{
"nx": {
"targets": {
"build": {
"executor": "@nx/esbuild:esbuild",
"options": {
"platform": "node",
"outputPath": "dist/apps/my-app",
"format": ["cjs"],
"main": "apps/my-app/src/main.ts",
"tsConfig": "apps/my-app/tsconfig.app.json"
}
}
}
}
}
```
{% /tabitem %}
{% tabitem label="Webpack" %}
Remove `generatePackageJson` from your webpack config:
```js
// apps/my-app/webpack.config.js
const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
const { join } = require('path');
module.exports = {
output: {
path: join(__dirname, '../../dist/apps/my-app'),
},
plugins: [
new NxAppWebpackPlugin({
target: 'node',
compiler: 'tsc',
main: './src/main.ts',
tsConfig: './tsconfig.app.json',
}),
],
};
```
{% /tabitem %}
{% tabitem label="Rollup / Vite" %}
Remove `generatePackageJson` from your rollup or vite build options.
With TS Solution Setup, the project `package.json` is used directly.
{% /tabitem %}
{% /tabs %}
### Step 3: Add prune targets
Add the `prune-lockfile`, `copy-workspace-modules`, and `prune` targets
to your project `package.json` as shown in the [set up prune targets](#set-up-prune-targets) section.
### Step 4: Update your Dockerfile
Replace references to the old generated `package.json` with the pruned output.
See the [use pruned output in Docker](#use-pruned-output-in-docker) section for a recommended Dockerfile structure.
@@ -9,6 +9,16 @@ filter: 'type:References'
[Express](https://expressjs.com/) is a mature, minimal, and an open source web framework for making web applications and
apis.
## Requirements
The `@nx/express` plugin supports the following package versions.
| Package | Supported Versions |
| --------- | ------------------ |
| `express` | ^4.21.2 |
[Nx generators](/docs/features/generate-code) install the latest supported versions automatically when scaffolding new projects.
## Create a New Workspace
To create a new workspace with a pre-created Express app, run the following command:
@@ -8,6 +8,26 @@ filter: 'type:References'
The Node Plugin contains generators and executors to manage Node applications within an Nx workspace. It provides:
## Requirements
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.
The Nx 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.
{% aside type="note" title="Other Node.js versions" %}
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.
{% /aside %}
| Nx Version | Node Version |
| -------------- | ------------------------ |
| 22.x (current) | 24.x, ^22.12.0, ^20.19.0 |
| 21.x | 24.x, ^22.12.0, ^20.19.0 |
| 20.x | 22.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 table should be considered the official compatibility matrix.
This table will be updated from time to time to reflect the latest versions of Node.js that are supported. If you encounter issues with Nx, please make sure you are using a supported version of Node.js before filing an issue.
## Setting Up @nx/node
### Installation
@@ -92,7 +112,7 @@ nx g @nx/node:application apps/my-new-app \
#### VSCode Integration
When generating Node applications, Nx automatically creates a VSCode debugging configuration for seamless development experience:
When generating Node applications, Nx automatically creates a VSCode debugging configuration:
- **Automatic setup**: A `.vscode/launch.json` file is created with pre-configured debugging settings.
- **Smart port allocation**: Debug ports are automatically assigned starting from 9229, preventing conflicts between multiple applications.
@@ -16,6 +16,18 @@ Nest.js is a framework designed for building scalable server-side applications.
Many conventions and best practices used in Angular applications can be also be used in Nest.
## Requirements
The `@nx/nest` plugin depends on `@nestjs/schematics` for code generation, which pins the supported NestJS major version.
| Nx Version | NestJS Version |
| -------------- | -------------- |
| 22.x (current) | ^11.0.0 |
| 21.x | ^11.0.0 |
| 20.x | ^10.0.0 |
[Nx generators](/docs/features/generate-code) install the latest supported versions automatically when scaffolding new projects.
## Setting Up @nx/nest
### Generating a new workspace
@@ -128,7 +140,7 @@ Nest applications also have the `inspect` flag set, so you can attach your debug
##### VSCode Integration
When generating Nest applications, Nx automatically creates a VSCode debugging configuration for seamless development experience:
When generating Nest applications, Nx automatically creates a VSCode debugging configuration:
- **Automatic setup**: A `.vscode/launch.json` file is created with pre-configured debugging settings.
- **Smart port allocation**: Debug ports are automatically assigned starting from 9229, preventing conflicts between multiple applications.
@@ -214,7 +226,7 @@ module.exports = {
Ensuring a smooth and reliable deployment of a Nest.js application in a production environment requires careful planning and the right strategy. Depending on your specific needs and infrastructure, you can choose from several deployment approaches. Below are four commonly used methods:
1. **Using Docker:**
Create a Dockerfile that specifies the application's environment and dependencies. Build a Docker image and optionally push it to a container registry. Deploy and run the Docker container on the server. Utilize the `@nx/node:setup-docker` generator to streamline the Docker setup process.
Create a Dockerfile that specifies the application's environment and dependencies. Build a Docker image and optionally push it to a container registry. Deploy and run the Docker container on the server. Use the `@nx/node:setup-docker` generator to set up Docker for your project.
2. **Installing Dependencies on the Server:**
Transfer the build artifacts to the server, install all dependencies using the package manager of your choice, and start the application. Ensure that [NxAppWebpackPlugin](/docs/technologies/build-tools/webpack/guides/webpack-plugins#nxappwebpackplugin) is configured with `generatePackageJson: true` so that the build artifacts directory includes `package.json` and `package-lock.json` (or the equivalent files for other package managers).
@@ -10,6 +10,17 @@ Expo is an open-source framework for apps that run natively on Android, iOS, and
Expo is a set of tools built on top of React Native. The Nx Plugin for Expo contains generators for managing Expo applications and libraries within an Nx workspace.
## Requirements
The `@nx/expo` plugin supports the following package versions.
| Package | Supported Versions |
| -------------- | -------------------- |
| `metro-config` | >= 0.82.0 |
| `expo` | ~53.0.0 \|\| ~54.0.0 |
[Nx generators](/docs/features/generate-code) install the latest supported versions automatically when scaffolding new projects.
## Setting Up Expo
To create a new workspace with Expo, run the following command:
@@ -12,6 +12,16 @@ The React plugin for Nx, `@nx/react`, provides generators for [applications and
You don't need the plugin to use React with Nx. Any project already benefits from [caching](/docs/features/cache-task-results), [task orchestration](/docs/features/run-tasks), and the [project graph](/docs/features/explore-graph). The plugin simplifies scaffolding and code generation.
## Requirements
The `@nx/react` plugin supports the following package versions.
| Package | Supported Versions |
| ------- | -------------------- |
| `react` | ^18.0.0 \|\| ^19.0.0 |
[Nx generators](/docs/features/generate-code) install the latest supported versions automatically when scaffolding new projects.
{% aside type="tip" title="Using a React Meta-Framework?" %}
If you're building with **Next.js** or **Remix**, use their dedicated plugins which include inferred task support. See the [Next.js plugin](/docs/technologies/react/next/introduction) or [Remix plugin](/docs/technologies/react/remix/introduction) hub pages. For **React Router** in framework mode, see the [React Router guide](/docs/technologies/react/guides/react-router).
{% /aside %}
@@ -12,6 +12,16 @@ The Next.js plugin for Nx, `@nx/next`, automatically [infers `build`, `dev`, and
You don't need the plugin to use Next.js with Nx. Any project already benefits from [caching](/docs/features/cache-task-results), [task orchestration](/docs/features/run-tasks), and the [project graph](/docs/features/explore-graph). The plugin adds automatic task inference, code generators, and simplified configuration.
## Requirements
The `@nx/next` plugin supports the following package versions.
| Package | Supported Versions |
| ------- | ------------------ |
| `next` | >=14.0.0 <17.0.0 |
[Nx generators](/docs/features/generate-code) install the latest supported versions automatically when scaffolding new projects.
## Setting Up @nx/next
### Add to an Existing Nx Workspace
@@ -1,12 +1,12 @@
---
title: Overview of the Nx React Native Plugin
description: The Nx Plugin for React Native contains generators for managing React Native applications and libraries within an Nx workspace. This page also explains how to configure React Native on your Nx workspace.
title: React Native Plugin for Nx
description: The Nx Plugin for React Native contains generators for managing React Native applications and libraries within an Nx workspace, including setup and configuration.
sidebar:
label: 'Introduction'
filter: 'type:References'
---
React Native brings React's declarative UI framework to iOS and Android. With React Native, you use native UI controls and have full access to the native platform.
React Native brings the React declarative UI framework to iOS and Android. With React Native, you use native UI controls and have full access to the native platform.
The Nx Plugin for React Native contains generators for managing React Native applications and libraries within an Nx workspace. It provides:
@@ -14,6 +14,17 @@ The Nx Plugin for React Native contains generators for managing React Native app
- Scaffolding for creating buildable libraries that can be published to npm.
- Utilities for automatic workspace refactoring.
## Requirements
The `@nx/react-native` plugin supports the following package versions.
| Package | Supported Versions |
| -------------- | ------------------ |
| `metro-config` | >= 0.82.0 |
| `react-native` | ~0.79.3 |
[Nx generators](/docs/features/generate-code) install the latest supported versions automatically when scaffolding new projects.
## Setting Up React Native
### Create a New Workspace
@@ -16,6 +16,16 @@ You don't need the plugin to use Remix with Nx. Any project already benefits fro
React Router is the successor to Remix. For new projects, consider using [React Router](/docs/technologies/react/guides/react-router) instead. Existing Remix projects continue to work with `@nx/remix`.
{% /aside %}
## Requirements
The `@nx/remix` plugin supports the following package versions.
| Package | Supported Versions |
| ---------------- | ------------------ |
| `@remix-run/dev` | ^2.17.3 |
[Nx generators](/docs/features/generate-code) install the latest supported versions automatically when scaffolding new projects.
## Setting Up @nx/remix
### Add to an Existing Nx Workspace
@@ -1,6 +1,6 @@
---
title: Overview of the Nx Cypress Plugin
description: The Nx Plugin for Cypress contains executors and generators that support e2e testing with Cypress. This page also explains how to configure Cypress on your Nx workspace.
title: Cypress Plugin for Nx
description: The Nx Plugin for Cypress contains executors and generators that support e2e testing with Cypress, including setup and configuration for your Nx workspace.
sidebar:
label: Introduction
filter: 'type:References'
@@ -15,6 +15,16 @@ Cypress is a test runner built for the modern web. It has a lot of great feature
- Network traffic control
- Screenshots and videos
## Requirements
The `@nx/cypress` plugin supports the following package versions.
| Package | Supported Versions |
| --------- | ------------------ |
| `cypress` | >= 13 < 16 |
[Nx generators](/docs/features/generate-code) install the latest supported versions automatically when scaffolding new projects.
## Setting Up @nx/cypress
> Info about [Cypress Component Testing can be found here](/docs/technologies/test-tools/cypress/guides/cypress-component-testing)
@@ -99,7 +109,7 @@ The options shown above control the names of the inferred Cypress tasks. The fol
### Splitting E2E tasks by file
The `@nx/cypress/plugin` will automatically split your e2e tasks by file. You can read more about the Atomizer feature [here](/docs/features/ci-features/split-e2e-tasks).
The `@nx/cypress/plugin` will automatically split your e2e tasks by file. Read more about the [Atomizer feature](/docs/features/ci-features/split-e2e-tasks).
To enable e2e task splitting, make sure there is a `ciWebServerCommand` property set in your `cypress.config.ts` file. It will look something like this:
@@ -264,7 +274,7 @@ If no `baseUrl` and no `devServerTarget` are provided, Cypress will expect to ha
If you need to fine tune your Cypress setup, you can do so by modifying `cypress.config.ts` in the project root. For
instance,
you can easily add your `projectId` to save all the screenshots and videos into your Cypress dashboard. The complete
you can add your `projectId` to save all the screenshots and videos into your Cypress dashboard. The complete
configuration is documented
on [the official website](https://docs.cypress.io/guides/references/configuration.html#Options).
@@ -276,7 +286,7 @@ If you need to pass a variable to Cypress that you don't want to commit to your
There are a handful of ways to pass environment variables to Cypress, but the most common is going to be via the [`cypress.env.json` file](https://docs.cypress.io/guides/guides/environment-variables#Option-1-configuration-file), the `-e` Cypress arg or the `env` option from the `@nx/cypress:cypress` executor in the [project configuration](/docs/reference/project-configuration#task-definitions-targets) or the command line.
Create a `cypress.env.json` file in the projects root (i.e. `apps/my-cool-app-e2e/cypress.env.json`). Cypress will automatically pick up this file. This method is helpful for configurations that you don't want to commit. Just don't forget to add the file to the `.gitignore` and add documentation so people in your repo know what values to populate in their local copy of the `cypress.env.json` file.
Create a `cypress.env.json` file in the projects root (i.e. `apps/my-cool-app-e2e/cypress.env.json`). Cypress will automatically pick up this file. This method is helpful for configurations that you don't want to commit. Make sure to add the file to the `.gitignore` and add documentation so people in your repo know what values to populate in their local copy of the `cypress.env.json` file.
Setting the `-e` Cypress arg or the `env` option from the `@nx/cypress:cypress` executor in the project configuration is a good way to add values you want to define that you don't mind committing to the repository, such as a base API URL.
@@ -14,6 +14,16 @@ Detox is gray box end-to-end testing and automation library for mobile apps. It
- Test Runner Independent
- Debuggable
## Requirements
The `@nx/detox` plugin supports the following package versions.
| Package | Supported Versions |
| ------- | ------------------ |
| `detox` | ^20.9.0 |
[Nx generators](/docs/features/generate-code) install the latest supported versions automatically when scaffolding new projects.
## Setting Up Detox
### Setup Environment
@@ -1,6 +1,6 @@
---
title: Overview of the Nx Jest Plugin
description: The Nx Plugin for Jest contains executors and generators that support testing projects using Jest. This page also explains how to configure Jest on your Nx workspace.
title: Jest Plugin for Nx
description: The Nx Plugin for Jest contains executors and generators that support testing projects using Jest, including setup and configuration for your Nx workspace.
sidebar:
label: Introduction
filter: 'type:References'
@@ -12,6 +12,16 @@ The `@nx/jest` plugin adds [inferred Jest targets](#configuration), a [Jest conf
You can use Jest with Nx without the plugin and still get [task caching](/docs/features/cache-task-results), [task orchestration](/docs/features/run-tasks), and the [project graph](/docs/features/explore-graph).
## Requirements
The `@nx/jest` plugin supports the following package versions.
| Package | Supported Versions |
| ------- | -------------------- |
| `jest` | ^29.0.0 \|\| ^30.0.0 |
[Nx generators](/docs/features/generate-code) install the latest supported versions automatically when scaffolding new projects.
## Setup
### Add to an existing workspace
@@ -234,7 +244,7 @@ Organize tests by feature to get better cache hits and more targeted CI runs. Se
Typically, in CI it's recommended to use `nx affected -t test --parallel=[# CPUs] --runInBand` for the best performance.
This is because each jest process creates workers based on system resources, running multiple projects via Nx and using jest workers will create too many processes overall causing the system to run slower than desired. Using the `--runInBand` flag tells jest to run in a single process. You can then leverage Nx parallelism to run multiple jest projects at once.
This is because each Jest process creates workers based on system resources, and running multiple projects via Nx with Jest workers will create too many processes overall, causing the system to run slower than desired. Using the `--runInBand` flag tells Jest to run in a single process. You can then use Nx parallelism to run multiple Jest projects at once.
### Batch Mode
@@ -1,6 +1,6 @@
---
title: Overview of the Nx Playwright Plugin
description: The Nx Plugin for Playwright contains executors and generators that support e2e testing with Playwright. This page also explains how to configure Playwright on your Nx workspace.
title: Playwright Plugin for Nx
description: The Nx Plugin for Playwright contains executors and generators that support e2e testing with Playwright, including setup and configuration for your Nx workspace.
sidebar:
label: Introduction
filter: 'type:References'
@@ -14,6 +14,16 @@ Playwright is a modern web test runner. With included features such as:
- Test generation
- Screenshots and videos
## Requirements
The `@nx/playwright` plugin supports the following package versions.
| Package | Supported Versions |
| ------------------ | ------------------ |
| `@playwright/test` | ^1.36.0 |
[Nx generators](/docs/features/generate-code) install the latest supported versions automatically when scaffolding new projects.
## Setting Up @nx/playwright
### Installation
@@ -68,7 +78,7 @@ The `targetName` and `ciTargetName` options control the name of the inferred Pla
### Splitting E2E Tests
`@nx/playwright/plugin` leverages Nx Atomizer to split your e2e tests into smaller tasks in a fully automated way. This allows for a much more efficient distribution of tasks in CI. You can read more about the Atomizer feature [here](/docs/features/ci-features/split-e2e-tasks).
`@nx/playwright/plugin` uses Nx Atomizer to automatically split your e2e tests into smaller tasks for more efficient distribution in CI. Read more about the [Atomizer feature](/docs/features/ci-features/split-e2e-tasks).
If you would like to disable Atomizer for Playwright tasks, set `ciTargetName` to `false`.
@@ -1,15 +1,30 @@
---
title: Nx Storybook Plugin Overview
title: Storybook Plugin for Nx
description: This is an overview page for the Storybook plugin in Nx. It explains what Storybook is and how to set it up in your Nx workspace.
sidebar:
label: Introduction
filter: 'type:References'
---
[Storybook](https://storybook.js.org) is a development environment for UI components. It allows you to browse a component library, view the different states of each component, and interactively develop and test components.
[Storybook](https://storybook.js.org) is a development environment for UI components. Browse a component library, view the different states of each component, and interactively develop and test components.
This guide will briefly walk you through using Storybook within an Nx workspace.
## Requirements
The `@nx/storybook` plugin supports the following package versions.
| Package | Supported Versions |
| ----------- | ------------------ |
| `storybook` | >=8.0.0 <11.0.0 |
[Nx generators](/docs/features/generate-code) install the latest supported versions automatically when scaffolding new projects.
<!-- The peerDependencies in @nx/storybook's package.json declares >=7.0.0 so that
users who still have Storybook 7 installed get a friendlier error from Nx
rather than a cryptic package-manager resolution failure. Storybook 7 is
no longer actively supported. -->
## Setting Up Storybook
### Installation
@@ -169,7 +184,7 @@ nx test-storybook project-name
### Anatomy of the Storybook setup
When running the Nx Storybook generator, it'll configure the Nx workspace to be able to run Storybook seamlessly. It'll create a project specific Storybook configuration.
When running the Nx Storybook generator, it configures the Nx workspace to run Storybook and creates a project-specific Storybook configuration.
The project-specific Storybook configuration is pretty much similar to what you would have for a non-Nx setup of Storybook. There's a `.storybook` folder within the project root folder.
@@ -1,6 +1,6 @@
---
title: Overview of the Nx Vitest Plugin
description: The Nx Plugin for Vitest contains executors and generators that support testing projects using Vitest. This page also explains how to configure Vitest on your Nx workspace.
title: Vitest Plugin for Nx
description: The Nx Plugin for Vitest contains executors and generators that support testing projects using Vitest, including setup and configuration for your Nx workspace.
sidebar:
label: Introduction
filter: 'type:References'
@@ -12,6 +12,16 @@ The `@nx/vitest` plugin adds [inferred Vitest targets](#configuration), a [proje
You can use Vitest with Nx without the plugin and still get [task caching](/docs/features/cache-task-results), [task orchestration](/docs/features/run-tasks), and the [project graph](/docs/features/explore-graph).
## Requirements
The `@nx/vite` plugin supports the following package versions.
| Package | Supported Versions |
| -------- | ------------------------------------------ |
| `vitest` | ^1.0.0 \|\| ^2.0.0 \|\| ^3.0.0 \|\| ^4.0.0 |
[Nx generators](/docs/features/generate-code) install the latest supported versions automatically when scaffolding new projects.
## Setup
### Add to an existing workspace
@@ -12,7 +12,15 @@ The TypeScript plugin for Nx, `@nx/js`, provides [generators for creating TypeSc
You don't need the plugin to use TypeScript with Nx, any project already benefits from [caching](/docs/features/cache-task-results), [task orchestration](/docs/features/run-tasks), and the [project graph](/docs/features/explore-graph). The plugin can help simplify setups and maintenance of TypeScript projects at scale.
See the [TypeScript compatibility matrix](/docs/reference/nodejs-typescript-compatibility#typescript-compatibility) for supported TypeScript versions.
## Requirements
Nx supports the latest version of TypeScript. TypeScript itself only officially supports its latest release under the [Modern Lifecycle Policy](https://learn.microsoft.com/en-us/lifecycle/policies/modern), but Nx maintains a wider range to give you time to upgrade. Support for an older TypeScript version may be dropped in an Nx major release, and support for a newer version may be added in an Nx minor release.
| Nx Version | TypeScript Version |
| -------------- | ------------------ |
| 22.x (current) | >= 5.4.2 < 5.10.0 |
| 21.x | >= 5.4.2 < 5.10.0 |
| 20.x | ~5.4.2 |
## Setting Up @nx/js plugin
@@ -1,6 +1,6 @@
---
title: Overview of the Nx Vue Plugin
description: The Nx Plugin for Vue contains generators for managing Vue applications and libraries within an Nx workspace. This page also explains how to configure Vue on your Nx workspace.
title: Vue Plugin for Nx
description: The Nx Plugin for Vue contains generators for managing Vue applications and libraries within an Nx workspace, including setup and configuration.
sidebar:
label: 'Introduction'
filter: 'type:References'
@@ -8,6 +8,16 @@ filter: 'type:References'
The Nx plugin for [Vue](https://vuejs.org/).
## Requirements
The `@nx/vue` plugin supports the following package versions.
| Package | Supported Versions |
| ------- | ------------------ |
| `vue` | ^3.5.13 |
[Nx generators](/docs/features/generate-code) install the latest supported versions automatically when scaffolding new projects.
## Setting Up @nx/vue
### Generating a new Workspace
@@ -1,6 +1,6 @@
---
title: Overview of the Nx Nuxt Plugin
description: The Nx Plugin for Nuxt contains generators for managing Nuxt applications within a Nx workspace. This page also explains how to configure Nuxt on your Nx workspace.
title: Nuxt Plugin for Nx
description: The Nx Plugin for Nuxt contains generators for managing Nuxt applications within an Nx workspace, including setup and configuration.
sidebar:
label: Introduction
filter: 'type:References'
@@ -8,6 +8,16 @@ filter: 'type:References'
The Nx plugin for [Nuxt](https://nuxt.com/).
## Requirements
The `@nx/nuxt` plugin supports the following package versions.
| Package | Supported Versions |
| ------- | ------------------- |
| `nuxt` | ^3.10.0 \|\| ^4.0.0 |
[Nx generators](/docs/features/generate-code) install the latest supported versions automatically when scaffolding new projects.
## Setting up a new Nx workspace with @nx/nuxt
You can create a new workspace that uses Nuxt with one of the following commands:
@@ -95,7 +105,7 @@ To perform end-to-end (E2E) testing on static HTML files using a test runner lik
This feature is particularly useful for testing in continuous integration (CI) pipelines, where resources may be constrained. Unlike the `serve` target, `serve-static` does not require a Nuxt's Nitro server to operate, making it more efficient and faster by eliminating background processes, such as file change monitoring.
To utilize the `serve-static` target for testing, run the following command:
To use the `serve-static` target for testing, run the following command:
```shell
nx serve-static my-nuxt-app-e2e
@@ -15,6 +15,7 @@ const { Content, headings } = await render(nxCli);
...nxCli.data,
title: 'Nx Commands',
description: 'Complete reference for Nx CLI',
tableOfContents: { minHeadingLevel: 2, maxHeadingLevel: 3 },
}}
headings={headings || []}
>
@@ -213,11 +213,12 @@ The Nx command line has various subcommands and options to help you manage your
Below is a complete reference for all available commands and their options.
You can run nx --help to view all available options.
## Available Commands
${flattenedCommands
.map(({ fullName, cmd, parentOptions }) => {
let section = `### \`nx ${fullName}\`\n`;
const isSubCommand = parentOptions !== undefined;
const headingLevel = isSubCommand ? '###' : '##';
let section = `${headingLevel} \`nx ${fullName}\`\n`;
section += cmd.description || 'No description available';
@@ -228,9 +229,20 @@ ${flattenedCommands
}
// Build the usage command string
const usageCmd = cmd.command
? cmd.command.replace('$0', fullName)
: fullName;
let usageCmd: string;
if (cmd.command && cmd.command.includes('$0')) {
// Has $0 placeholder - replace with full name
usageCmd = cmd.command.replace('$0', fullName);
} else if (cmd.command && parentOptions !== undefined) {
// Sub-command without $0: use fullName, append positional args from cmd.command
const firstSpaceIdx = cmd.command.indexOf(' ');
usageCmd =
firstSpaceIdx !== -1
? fullName + cmd.command.substring(firstSpaceIdx)
: fullName;
} else {
usageCmd = cmd.command || fullName;
}
section += `\n\n**Usage:**
\`\`\`bash
@@ -5,7 +5,6 @@ authors: ['Victor Savkin', 'Philip Fulcher']
tags: ['nx']
cover_image: /blog/images/2026-01-09/header.avif
description: 'Discover why AI agents underperform in polyrepos and how Nx monorepos unlock 30% productivity gains. Learn why architecture matters for AI agent success.'
pinned: true
---
## Nx doesn't just make monorepos manageable. It makes AI agents effective.
@@ -15,6 +15,7 @@ metrics:
label: 'projects unified'
- value: '2x faster'
label: 'CI pipelines'
pinned: true
---
Broadcom is a global technology leader providing semiconductor, enterprise software, and security solutions to thousands of customers worldwide. Their engineering organization manages a wide portfolio of complex applications, including the [VMware](https://www.vmware.com/) suite of products. Their frontend architecture team has spent nearly a decade figuring out how to manage this portfolio efficiently.
@@ -5,6 +5,7 @@ authors: ['Max Kless']
tags: [nx, ai, mcp]
cover_image: /blog/images/articles/bg-mcp-to-skills.avif
description: 'How the shift from MCP tools to agent skills changed the way AI assistants work with Nx monorepos — and why MCP still matters.'
pinned: true
---
Remember when MCP was the hot new thing? That was barely a year ago. We built [MCP tools for Nx](/blog/nx-made-cursor-smarter) — surfacing project graphs, generator schemas, task pipelines directly into LLM conversations — and for the first time AI assistants could actually _understand_ your workspace. We shipped integrations for Cursor, VS Code Copilot, and JetBrains, and it worked well.
@@ -9,9 +9,8 @@ authors: ['Jeff Cross', 'Juri Strumpflohner']
tags: [webinar]
cover_image: /blog/images/2026-02-18/Feb2026-webinar-card.avif
time: 2pm ET/7pm UTC
status: Upcoming
status: Past - Gated
registrationUrl: https://go.nx.dev/feb2026-webinar
pinned: true
---
**Feb 18, 2026 - 2pm ET/7pm UTC**
@@ -22,4 +21,4 @@ Monorepo architecture has evolved significantly in the past few years, yet the l
This webinar will provide a clear framework for understanding monorepos in 2026, cutting through the noise to explain how they deliver measurable impact. Particularly for organizations working to ship at AI-accelerated speeds.
{% call-to-action title="Register today!" url="https://go.nx.dev/feb2026-webinar" description="Save your spot" /%}
{% call-to-action title="Download the recording!" url="https://go.nx.dev/feb2026-webinar" description="Sign up to gain access" /%}
@@ -0,0 +1,200 @@
---
title: 'A Monorepo Is NOT a Monolith'
slug: 'monorepo-is-not-monolith'
authors: ['Victor Savkin', 'Juri Strumpflohner']
tags: [nx, monorepo]
cover_image: /blog/images/articles/monorepo-is-not-monolith-bg.avif
hideCoverImage: true
description: 'Common objections to monorepos debunked: they are not monoliths, they scale, and they work great with AI.'
---
I've been building dev tools for monorepos and helping companies use them for years. **And I've been hearing similar objections to the monorepo idea from many teams:**
- It forces us to release together. Monoliths are bad.
- It lets other teams change my code without my knowing.
- It creates a big ball of mud. It makes applications hard to understand and maintain.
- It doesn't scale.
- AI tools can't handle large monorepos.
Many of them arise from confusion, often after trying a basic workspace setup, seeing a bunch of problems, and concluding that it is not a viable approach for multi-project-multi-team scenarios.
In this article, **I will show what a proper monorepo setup looks like and talk about common misconceptions related to monorepos.**
Monorepos are not a silver bullet. Nothing is. But hopefully **at the end of this article, you will have a clear understanding of the benefits a monorepo brings, what _actual_ challenges you will face, and if it is the right approach for your organization.**
_For the examples in this post, I will use [Nx](/docs/getting-started/intro), an extensible build system optimized for monorepos. But the concepts apply broadly to any monorepo tooling._
{% toc /%}
## What is a Monorepo?
**Monorepo-style development is a software development approach where**:
- You develop multiple projects in the same repository.
- The projects can depend on each other, so they can share code.
- When you make a change, you do not rebuild or retest every project in the monorepo. Instead, you only rebuild and retest the projects that can be affected by your change.
That last point is crucial for two reasons:
**It keeps CI fast.** On a large scale, running only what's affected can be orders of magnitude faster than rebuilding everything. Layer on [remote caching](/docs/concepts/how-caching-works) so work that's already been done is never repeated, and [distribute tasks across machines](/docs/features/ci-features/distribute-task-execution) intelligently, and you have a CI pipeline that scales with your codebase rather than against it.
**It gives teams independence.** If two projects A and B do not depend on each other, they cannot affect each other. Team A will be able to develop their project, test it, build it, merge PRs into master without ever having to run any code written by Team B. Team B can have flaky tests, poorly typed code, broken code, broken tests. None of it matters to Team A.
## Misconceptions
### A Monorepo Is NOT a Monolith
> "Will we have to release all on the same day? I don't like monoliths!"
It's a common misconception, which comes from a strong association of a repository with a deployment artifact.
But it is not hard to see that **where you develop your code and what/when you deploy are actually orthogonal concerns**. Google, for instance, has thousands of applications in its monorepo, but obviously, all of them are not released together.
Moreover, it's actually a good CI/CD practice to build and store artifacts when doing CI, and deploy the stored artifacts to different environments during the deployment phase. In other words, **deploying an application should not require access to any repository**, one or many.
**So a monorepo is not a monolith. Quite the contrary, because monorepos simplify code sharing and cross-project refactorings, they significantly lower the cost of creating libs, microservices and microfrontends. So adopting a monorepo often enables more deployment flexibility.**
### It lets other teams change my code without my knowing
> "Another team can break my app, without my knowing, right before the release!"
This misconception originates from folks only using repository settings to control access and permissions. Not many know that **many tools let you configure ownership on the folder basis**.
For instance, GitHub has a feature called [CODEOWNERS](https://help.github.com/en/articles/about-code-owners). You can provision a file that looks like this:
```rb
apps/app-a/* @susan
apps/app-b/* @bob
```
With this configuration, if you have a PR updating App A, Susan will have to approve it. If the PR touches only App B, Bob will have to approve it. And if the PR touches A and B, both Susan and Bob will have to approve it.
Nx takes this further with [`@nx/owners`](/docs/reference/owners/overview), which lets you define ownership based on **projects and tags** rather than raw file paths. Ownership rules are defined in `nx.json` or per-project `package.json` (or `project.json`) and compiled into standard CODEOWNERS files via `nx sync`. This means ownership stays in sync with your project structure automatically, instead of requiring you to manually maintain path patterns.
You actually get more control over code ownership. Look here:
![Two teams with shared libraries and ownership boundaries](/blog/images/articles/monorepo-misconceptions-codeowners.svg)
We have two teams in the org. Team B want to share code between their applications, so they created a library shared-b. This library is private, so they don't want Team A to depend on it. Why? Because if it happens, the teams will get coupled to each other, and Team B will have to account for Team A when changing the shared library.
In a multi-repo setup, nothing prevents Team A from adding shared-b to their `package.json`. It is hard for Team B to know about it because it is done in a repository they do not control. Most monorepo tools (including Nx) allow you to define the visibility of a library in a precise way. So when trying to import shared-b, you see this:
![Visibility constraint error when importing a private library](/blog/images/articles/monorepo-misconceptions-visibility.avif)
### It creates a big ball of mud
> "Even one of our applications is barely manageable. If we put five of them in the same repo, no one will be able to understand anything at all!"
This misconception comes from the fact that in most repositories any file can import any other file. Folks try to impose some structure during code reviews, but things do not stay well-defined for long, and the dependency graph gets muddled.
Everyone knows this. Open a mid-sized project (maybe 50k lines of code), and draw a dependency diagram of its main components and how they depend on each other. Now check it against the repository. You will find a lot of "unexpected" edges in the graph.
With Nx, you can create libraries that have well-defined public APIs. And because creating libraries takes just a few seconds, folks tend to create more libraries. So a typical application will be partitioned into dozens of libraries, which can depend on each other only through their public APIs.
![Application partitioned into well-defined libraries](/blog/images/articles/monorepo-misconceptions-libs.avif)
Nx also automates the generation of the dependency graph which you can view by running `nx graph`.
![Nx dependency graph visualization](/blog/images/articles/monorepo-misconceptions-graph.svg)
In opposite to the diagram created by some architect you can find in your wiki, which became outdated the day after it was created, this graph is correct and up to date.
You can also [enforce module boundaries](/docs/features/enforce-module-boundaries) by adding tags to your projects and defining dependency constraints. For instance, you can tag projects with `scope:client` or `scope:shared` and create rules like "client-scoped projects can only depend on client or shared projects." These constraints are enforced at lint time via the `@nx/enforce-module-boundaries` ESLint rule, meaning violations are caught before code is even committed. You can statically guarantee that presentation components cannot depend on state management code, or that a team's private library cannot be imported by another team.
![Module boundary constraint violation](/blog/images/articles/monorepo-misconceptions-boundaries.avif)
Funny enough, this is another case where using monorepos results in the opposite of what a lot of folks think.
### It does not scale
> "Am I to expect 5 hour CI time?"
Rebuilding and retesting everything on every commit is slow. It does not scale beyond a handful of projects. But as mentioned above, when using monorepo tools, you only rebuild and retest what is affected.
Modern monorepo tooling provides a layered scaling strategy that you can adopt incrementally:
1. **Affected commands**: only run tasks for projects impacted by your change. This alone can cut CI time dramatically.
2. **Local and remote caching**: never redo work that's already been done. [Remote caching](/docs/concepts/how-caching-works) (via Nx Replay) shares results across your team and CI, so if a teammate already built that library, you get the result instantly.
3. **Distributed task execution**: when a single machine isn't enough, [Nx Agents](/docs/features/ci-features/distribute-task-execution) dynamically distribute tasks across multiple machines based on the dependency graph and historical runtime data.
4. **Task atomization**: large test suites become a bottleneck even with distribution. The [Atomizer](/docs/features/ci-features/split-e2e-tasks) splits monolithic e2e or integration test targets into per-file tasks that can run in parallel. A 10-minute e2e suite becomes five 2-minute tasks spread across agents.
Each layer builds on the previous one, and you only adopt what you need at your current scale.
> "Is git going to break?"
This concern is not truly unjustified. If your repo has millions of files, many tools you know and love, including plain Git, will stop working. However, most monorepos do not have thousands of apps. They have a dozen apps built by a single org. Thousands of files, millions of lines of code. All the tools you use can handle this without any problems.
Microsoft released [Scalar](https://github.com/microsoft/scalar), a tool that enables Git to work with enormous repos. Azure Pipelines, BitBucket, and GitHub all support it.
### AI doesn't work in monorepos
> "My codebase is too big, AI tools will be overwhelmed!"
A common concern is that AI coding agents can't handle monorepos because there's too much code, too many projects, too much context. In practice, the opposite is true. Monorepo tooling provides exactly the structure AI agents need: a project graph that maps dependencies, consistent conventions across projects, and clear module boundaries. Instead of an agent guessing how your 15 repos relate to each other, it can query the graph and understand the architecture instantly.
Nx is built to work with AI agents. The CLI is optimized for agent navigation, and dedicated [Nx agent skills](/blog/nx-ai-agent-skills) teach your AI how to explore the workspace, run tasks, scaffold code following your conventions, and even monitor CI pipelines. On the CI side, [self-healing CI](/docs/features/ci-features/self-healing-ci) uses AI to automatically detect and fix pipeline failures, posting fixes as PR comments or auto-applying high-confidence patches. Monorepos don't overwhelm AI: they give it the structure to actually be effective.
If you want to dive deeper into how Nx and AI work together, check out:
- [Nx and AI: Why They Work so Well Together](/blog/nx-and-ai-why-they-work-together)
- [End to End Autonomous AI Agent Workflows with Nx](/blog/autonomous-ai-workflows-with-nx)
- [Autonomous Agents at Scale](/blog/ai-agents-and-continuity)
{% callout type="note" title="Dive deeper" %}
We cover additional misconceptions (polyglot support, lockstep versioning, dependency hell, and more) in [10 Monorepo Myths Debunked](/blog/monorepo-myths-debunked).
{% /callout %}
## Real Challenges
The things listed above are misconceptions. It does not mean that monorepos are perfect. They come with their own challenges.
### Trunk-based development
Monorepos and long-lived feature branches do not play together nicely. Chances are you will have to adopt some form of [trunk-based development](https://trunkbaseddevelopment.com/). Transitioning to this style of development can be challenging for some teams, partially because they have to adopt new practices such as feature toggles.
Trunk-based development results in better quality code and higher velocity regardless of repo size, but it is still something you must take into account.
### CI
Moving to a monorepo requires you to rethink how you do continuous integration. You are no longer building a single app: you are building only the things affected by your change, caching aggressively, and potentially distributing work across machines.
The tooling gap that existed in 2019 has largely closed. Nx Cloud provides [remote caching](/docs/concepts/how-caching-works), [distributed task execution](/docs/features/ci-features/distribute-task-execution), [task atomization](/docs/features/ci-features/split-e2e-tasks), and [self-healing CI](/docs/features/ci-features/self-healing-ci) out of the box. The challenge is no longer "can I make this work" but rather tuning your pipeline as your codebase grows.
### Large-scale changes
Monorepos make some large-scale changes a lot simpler: you can refactor ten apps made out of a hundred libs, verify that they all work before committing the change.
But they force you to think through large-scale changes more and make some of them more difficult. For instance, if you change a shared library, you will affect all the applications that depend on it. If it is a breaking change, and it cannot be automated, you will have to make the change in a backward-compatible way. You will have to create two versions of the parameter/method/class/package and help folks move from the old version to the new one.
## Let's Recap
**Monorepos are known for the following benefits:**
- Everything at that current commit works together. Changes can be verified across all affected parts of the organization.
- Easy to split code into composable modules
- Easier dependency management
- One toolchain setup
- Code editors and IDEs are "workspace" aware
- Consistent developer experience
**In spite of what folks say, they also:**
- Give you more deployment flexibility
- Allow you to set up precise ownership policies
- Provide more structure to your source code
- Scale well with the right tooling (affected, caching, distribution, atomization)
- Complement AI-assisted development rather than hinder it
**But they come with some challenges:**
- Trunk-based development is a lot more important
- Require more sophisticated CI setup (though modern tooling handles most of it)
- Require you to think about large-scale changes
## Learn More
- [Nx Docs](/docs/getting-started/intro)
- [Nx Community Discord](https://go.nx.dev/community)
- [X / Twitter](https://twitter.com/nxdevtools)
- [Nx GitHub](https://github.com/nrwl/nx)
- [Nx YouTube Channel](https://www.youtube.com/@nxdevtools)
@@ -0,0 +1,33 @@
---
title: 'Nx Joins the Linux Foundation and the Agentic AI Foundation'
slug: nx-joins-linux-foundation-and-aaif
authors: ['Philip Fulcher']
tags: ['nx']
cover_image: /blog/images/2026-02-25/header.avif
description: 'Nx joins the Linux Foundation and Agentic AI Foundation (AAIF) to help shape open standards for AI-powered development. Learn how the intersection of agentic AI and build tooling will transform software development workflows, and why Nx is committing to open collaboration with Anthropic, AWS, Google, and Microsoft to build the future of autonomous AI agents in developer tooling.'
pinned: true
---
As AI agents become central to how developers build and scale software, the need for open standards, shared tooling, and transparent governance has never been greater. Today, we're excited to announce that Nx is now a member of the [Linux Foundation](https://www.linuxfoundation.org) and the [Agentic AI Foundation (AAIF)](https://aaif.io).
## Building the Future of Agentic AI
The software development landscape is shifting. Agentic AI — autonomous systems that can plan, coordinate, and act across tools and codebases — is quickly moving from research concept to production reality. The companies and communities that define the standards for this new era will shape how millions of developers work for years to come.
The Linux Foundation has long served as the neutral, trusted home for the open source projects that power global infrastructure. The Agentic AI Foundation, formed in December 2025 under the Linux Foundation umbrella, extends that mission into the age of AI agents. Anchored by foundational projects like Anthropic's Model Context Protocol (MCP), Block's goose, and OpenAI's AGENTS.md, the AAIF is where the open standards for agentic AI are being built.
Nx is joining both foundations because we believe the future of developer tooling is inseparable from the future of agentic AI, and that future must be open.
## The Intersection of Agentic AI and Build Tooling
Nx has spent years building intelligent tooling that helps developers and teams manage complex codebases at scale. Our monorepo platform is used by organizations worldwide, empowering software developers across the JavaScript, TypeScript, and broader polyglot ecosystem.
As AI agents increasingly operate within these environments — navigating dependency graphs, orchestrating builds, generating and modifying code — the intersection of agentic AI and build tooling becomes critical. Nx is uniquely positioned to contribute to the standards and practices that ensure these agents work reliably, predictably, and at scale within real-world development workflows.
## What's Ahead
By joining the Linux Foundation and the AAIF, we're committing to collaborating with leaders across the ecosystem to advance open standards for agentic workflows. That means participating in working groups, contributing to shared specifications, and helping ensure that the tooling developers rely on every day is designed to work seamlessly with the next generation of AI-powered development.
We're looking forward to working alongside Anthropic, AWS, Google, Microsoft, and the many other organizations shaping this space. The era of agentic AI is here, and we're proud to help build it — together, and in the open.
_To learn more about the Linux Foundation, visit [linuxfoundation.org](http://linuxfoundation.org). To learn more about the Agentic AI Foundation, visit [aaif.io](http://aaif.io). And to learn more about Nx, visit [nx.dev](http://nx.dev)._
Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 421 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

@@ -0,0 +1,38 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 220" width="400" height="220" font-family="system-ui, -apple-system, sans-serif" font-size="13">
<!-- Row 1: e2e apps -->
<rect x="10" y="10" width="100" height="36" rx="3" fill="#f5f5f5" stroke="#888" stroke-width="1"/>
<text x="60" y="33" text-anchor="middle">app-a-e2e</text>
<rect x="150" y="10" width="100" height="36" rx="3" fill="#f5f5f5" stroke="#888" stroke-width="1"/>
<text x="200" y="33" text-anchor="middle">app-b2-e2e</text>
<rect x="290" y="10" width="100" height="36" rx="3" fill="#f5f5f5" stroke="#888" stroke-width="1"/>
<text x="340" y="33" text-anchor="middle">app-b1-e2e</text>
<!-- Row 2: apps -->
<rect x="10" y="90" width="100" height="36" rx="3" fill="#f5f5f5" stroke="#888" stroke-width="1"/>
<text x="60" y="113" text-anchor="middle">app-a</text>
<rect x="150" y="90" width="100" height="36" rx="3" fill="#f5f5f5" stroke="#888" stroke-width="1"/>
<text x="200" y="113" text-anchor="middle">app-b2</text>
<rect x="290" y="90" width="100" height="36" rx="3" fill="#f5f5f5" stroke="#888" stroke-width="1"/>
<text x="340" y="113" text-anchor="middle">app-b1</text>
<!-- Row 3: shared lib (ellipse) -->
<ellipse cx="230" cy="185" rx="70" ry="22" fill="#fff3cd" stroke="#d4a017" stroke-width="1.5"/>
<text x="230" y="190" text-anchor="middle">shared-b</text>
<!-- Arrows: e2e -> apps -->
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#555"/>
</marker>
<line x1="60" y1="46" x2="60" y2="88" stroke="#555" stroke-width="1.2" marker-end="url(#arrow)"/>
<line x1="200" y1="46" x2="200" y2="88" stroke="#555" stroke-width="1.2" marker-end="url(#arrow)"/>
<line x1="340" y1="46" x2="340" y2="88" stroke="#555" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Arrows: app-b2 and app-b1 -> shared-b -->
<line x1="200" y1="126" x2="218" y2="162" stroke="#555" stroke-width="1.2" marker-end="url(#arrow)"/>
<line x1="340" y1="126" x2="248" y2="164" stroke="#555" stroke-width="1.2" marker-end="url(#arrow)"/>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

@@ -0,0 +1,57 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 420 340" width="420" height="340" font-family="system-ui, -apple-system, sans-serif" font-size="13">
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#555"/>
</marker>
<!-- Row 1: e2e apps -->
<rect x="60" y="10" width="110" height="36" rx="3" fill="#f5f5f5" stroke="#888" stroke-width="1"/>
<text x="115" y="33" text-anchor="middle">agent-e2e</text>
<rect x="260" y="10" width="110" height="36" rx="3" fill="#f5f5f5" stroke="#888" stroke-width="1"/>
<text x="315" y="33" text-anchor="middle">tickets-e2e</text>
<!-- Row 2: apps -->
<rect x="80" y="90" width="90" height="36" rx="3" fill="#f5f5f5" stroke="#888" stroke-width="1"/>
<text x="125" y="113" text-anchor="middle">agent</text>
<rect x="270" y="90" width="90" height="36" rx="3" fill="#f5f5f5" stroke="#888" stroke-width="1"/>
<text x="315" y="113" text-anchor="middle">tickets</text>
<!-- Row 3: libs -->
<rect x="10" y="180" width="90" height="36" rx="3" fill="#f5f5f5" stroke="#888" stroke-width="1"/>
<text x="55" y="203" text-anchor="middle">agent-api</text>
<rect x="140" y="180" width="90" height="36" rx="3" fill="#f5f5f5" stroke="#888" stroke-width="1"/>
<text x="185" y="203" text-anchor="middle">api</text>
<ellipse cx="320" cy="198" rx="60" ry="20" fill="#e8e8e8" stroke="#888" stroke-width="1"/>
<text x="320" y="203" text-anchor="middle">ticket-list</text>
<!-- Row 4: data lib -->
<ellipse cx="210" cy="295" rx="55" ry="20" fill="#e8e8e8" stroke="#888" stroke-width="1"/>
<text x="210" y="300" text-anchor="middle">data</text>
<!-- Arrows: e2e -> apps -->
<line x1="115" y1="46" x2="122" y2="88" stroke="#555" stroke-width="1.2" marker-end="url(#arrow)"/>
<line x1="315" y1="46" x2="315" y2="88" stroke="#555" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Arrows: agent -> agent-api, api -->
<line x1="105" y1="126" x2="70" y2="178" stroke="#555" stroke-width="1.2" marker-end="url(#arrow)"/>
<line x1="145" y1="126" x2="175" y2="178" stroke="#555" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Arrows: tickets -> api, ticket-list -->
<line x1="295" y1="126" x2="205" y2="178" stroke="#555" stroke-width="1.2" marker-end="url(#arrow)"/>
<line x1="320" y1="126" x2="320" y2="176" stroke="#555" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Arrows: agent-api -> data -->
<line x1="75" y1="216" x2="170" y2="285" stroke="#555" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Arrows: api -> data -->
<line x1="190" y1="216" x2="205" y2="273" stroke="#555" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Arrows: ticket-list -> data -->
<line x1="295" y1="215" x2="248" y2="282" stroke="#555" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Arrows: tickets -> data (wide curve around ticket-list) -->
<path d="M 355,126 C 415,160 415,280 262,293" stroke="#555" stroke-width="1.2" fill="none" marker-end="url(#arrow)"/>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

+1 -1
View File
@@ -11,7 +11,7 @@ width="100%" /%}
{% cards cols="2" %}
{% card title="TypeScript Project References & Workspaces Support" type="document" url="/docs/concepts/typescript-project-linking" /%}
{% card title="New @nx/rsbuild Plugin" type="document" url="/docs/technologies/angular/angular-rsbuild/create-config" /%}
{% card title="New @nx/rsbuild Plugin" type="document" url="/docs/technologies/angular/angular-rsbuild/introduction" /%}
{% card title="Support for Rollup TypeScript Config" type="external" url="https://github.com/nrwl/nx/pull/28240" /%}
{% card title="Expo v52 Support" type="external" url="https://github.com/nrwl/nx/pull/29142" /%}
{% /cards %}
@@ -82,7 +82,7 @@ describe('Angular Projects - Build and Test', () => {
console.log(
`The current es2015 bundle size is ${es2015BundleSize / 1000} KB`
);
expect(es2015BundleSize).toBeLessThanOrEqual(221000);
expect(es2015BundleSize).toBeLessThanOrEqual(223000);
// check unit tests
runCLI(
+2 -2
View File
@@ -5,8 +5,8 @@
"projectType": "application",
"implicitDependencies": [
"gradle",
"gradle-project-graph",
"gradle-batch-runner"
":gradle-project-graph",
":gradle-batch-runner"
],
"// targets": "to see all targets run: nx show project e2e-gradle --web",
"targets": {}
+4 -4
View File
@@ -36,14 +36,14 @@ describe('Gradle Plugin V1', () => {
});
afterAll(() => cleanupProject());
it('should build', () => {
it('should build without batch mode', () => {
const projects = runCLI(`show projects`);
expect(projects).toContain('app');
expect(projects).toContain('list');
expect(projects).toContain('utilities');
expect(projects).toContain(gradleProjectName);
const buildOutput = runCLI('build app', { verbose: true });
const buildOutput = runCLI('build app --no-batch', { verbose: true });
expect(buildOutput).toContain('nx run list:build');
expect(buildOutput).toContain(':list:classes');
expect(buildOutput).toContain('nx run utilities:build');
@@ -56,7 +56,7 @@ describe('Gradle Plugin V1', () => {
);
});
it('should track dependencies for new app', () => {
it('should track dependencies for new app without batch mode', () => {
if (type === 'groovy') {
createFile(
`app2/build.gradle`,
@@ -94,7 +94,7 @@ dependencies {
}
);
let buildOutput = runCLI('build app2', { verbose: true });
let buildOutput = runCLI('build app2 --no-batch', { verbose: true });
// app2 depends on app
expect(buildOutput).toContain('nx run app:build');
expect(buildOutput).toContain(':app:classes');
+11 -7
View File
@@ -23,14 +23,14 @@ describe('Gradle', () => {
});
afterAll(() => cleanupProject());
it('should build', () => {
it('should build without batch mode', () => {
const projects = runCLI(`show projects`);
expect(projects).toContain('app');
expect(projects).toContain('list');
expect(projects).toContain('utilities');
expect(projects).toContain(gradleProjectName);
let buildOutput = runCLI('build app', { verbose: true });
let buildOutput = runCLI('build app --no-batch', { verbose: true });
expect(buildOutput).toContain(':list:classes');
expect(buildOutput).toContain(':utilities:classes');
@@ -48,7 +48,7 @@ describe('Gradle', () => {
expect(bootJarOutput).toContain(':app:bootJar');
});
it('should track dependencies for new app', () => {
it('should track dependencies for new app without batch mode', () => {
if (type === 'groovy') {
createFile(
`app2/build.gradle`,
@@ -86,7 +86,7 @@ dependencies {
}
);
let buildOutput = runCLI('build app2', { verbose: true });
let buildOutput = runCLI('build app2 --no-batch', { verbose: true });
// app2 depends on app
expect(buildOutput).toContain(':app:classes');
expect(buildOutput).toContain(':list:classes');
@@ -109,8 +109,12 @@ dependencies {
});
expect(() => {
runCLI('run app:test-ci--MessageUtilsTest', { verbose: true });
runCLI('run list:test-ci--LinkedListTest', { verbose: true });
runCLI('run app:test-ci--MessageUtilsTest --no-batch', {
verbose: true,
});
runCLI('run list:test-ci--LinkedListTest --no-batch', {
verbose: true,
});
}).not.toThrow();
});
@@ -153,7 +157,7 @@ dependencies {
expect(output).toContain('gradle-classes');
// Verify prefixed target works
const buildOutput = runCLI('run app:gradle-build');
const buildOutput = runCLI('run app:gradle-build --no-batch');
expect(buildOutput).toContain('BUILD SUCCESSFUL');
});
@@ -91,7 +91,7 @@ export function createGradleProject(
e2eConsoleLogger(
execSync(
`${gradleCommand} :project-graph:publishToMavenLocal -PskipSign=true`,
`${gradleCommand} :gradle-project-graph:publishToMavenLocal -PskipSign=true`,
{
cwd: `${__dirname}/../../../..`,
}
+1 -3
View File
@@ -11,9 +11,7 @@ import {
updateJson,
} from '@nx/e2e-utils';
// TODO: Re-enable once @microsoft/api-extractor ESM import issue is resolved
// See: https://github.com/qmhc/unplugin-dts/issues/461
xdescribe('JS - TS solution setup', () => {
describe('JS - TS solution setup', () => {
beforeAll(() => {
newProject({
packages: ['@nx/js'],
+5 -5
View File
@@ -46,9 +46,9 @@ describe('Maven', () => {
expect(output).toContain('- install-ci:');
});
it('should build Maven project with dependencies', () => {
it('should build Maven project with dependencies without batch mode', () => {
// Build app which depends on lib, which depends on utils
let buildOutput = runCLI('run app:install', { verbose: true });
let buildOutput = runCLI('run app:install --no-batch', { verbose: true });
// Should build dependencies first
expect(buildOutput).toContain('BUILD SUCCESS');
@@ -60,8 +60,8 @@ describe('Maven', () => {
);
});
it('should run tests for Maven project', () => {
const testOutput = runCLI('run utils:test', { verbose: true });
it('should run tests for Maven project without batch mode', () => {
const testOutput = runCLI('run utils:test --no-batch', { verbose: true });
expect(testOutput).toContain('BUILD SUCCESS');
});
@@ -118,7 +118,7 @@ describe('Maven', () => {
expect(output).toContain('- mvn-install-ci:');
// Verify prefixed target works
const buildOutput = runCLI('run app:mvn-compile');
const buildOutput = runCLI('run app:mvn-compile --no-batch');
expect(buildOutput).toContain('BUILD SUCCESS');
});
});

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