
Nx Import
- 1.9k installs
- 27 repo stars
- Updated July 23, 2026
- nrwl/nx-ai-agents-config
nx-import is a skill that Import, merge, or combine repositories into an Nx workspace using nx import. USE WHEN the user asks to adopt Nx across repos, move projects into a monorepo, or bring code/history from another re
About
The nx-import skill helps with Import, merge, or combine repositories into an Nx workspace using nx import. USE WHEN the user asks to adopt Nx across repos, move projects into a monorepo, or bring code/history from another repository. Key workflows include Quick Start; Import Strategy; Directory Conventions; Application vs Library Detection. Documented capabilities cover `nx import` brings code from a source repository or folder into the current workspace, preserving commit history.; After nx `22.6.0`, `nx import` responds with .ndjson outputs and follow-up questions. For earlier versions, always run with `--no-interactive` and specify all flags directly.; Run `nx import --help` for available options.; Make sure the destination directory is empty before importing.; https://nx.dev/docs/guides/adopting-nx/import-project. Agents should invoke it when users ask about nx import or mention triggers defined in the skill frontmatter. Follow the SKILL.md steps, reference files, and output formats rather than improvising outside documented scope.
- Quick Start
- `nx import` brings code from a source repository or folder into the current workspace, preserving commit history.
- After nx `22.6.0`, `nx import` responds with .ndjson outputs and follow-up questions. For earlier versions, always run w
- Run `nx import --help` for available options.
- Make sure the destination directory is empty before importing.
Nx Import by the numbers
- 1,868 all-time installs (skills.sh)
- +58 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #117 of 1,435 DevOps & CI/CD skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
nx-import capabilities & compatibility
- Capabilities
- quick start · `nx import` brings code from a source repository · after nx `22.6.0`, `nx import` responds with .nd · run `nx import help` for available options. · make sure the destination directory is empty bef
- Use cases
- planning · research
What nx-import says it does
Import, merge, or combine repositories into an Nx workspace using nx import. USE WHEN the user asks to adopt Nx across repos, move projects into a monorepo, or bring code/history f
npx skills add https://github.com/nrwl/nx-ai-agents-config --skill nx-importAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1.9k |
|---|---|
| repo stars | ★ 27 |
| Security audit | 3 / 3 scanners passed |
| Last updated | July 23, 2026 |
| Repository | nrwl/nx-ai-agents-config ↗ |
How do I apply nx-import for nx import tasks?
Import, merge, or combine repositories into an Nx workspace using nx import. USE WHEN the user asks to adopt Nx across repos, move projects into a monorepo, or bring code/history f
Who is it for?
Teams using nx-import as documented in the skill repository.
Skip if: Tasks outside the nx-import scope in SKILL.md.
When should I use this skill?
User mentions nx-import, nx-import, or related skill triggers.
What you get
Structured guidance and deliverables from the nx-import SKILL.md workflow.
- Imported Nx project configuration
- ESLint lint targets per project
Files
Quick Start
nx importbrings code from a source repository or folder into the current workspace, preserving commit history.- After nx
22.6.0,nx importresponds with .ndjson outputs and follow-up questions. For earlier versions, always run with--no-interactiveand specify all flags directly. - Run
nx import --helpfor available options. - Make sure the destination directory is empty before importing.
EXAMPLE: target has libs/utils and libs/models; source has libs/ui and libs/data-access — you cannot import libs/ into libs/ directly. Import each source library individually.
Primary docs:
- https://nx.dev/docs/guides/adopting-nx/import-project
- https://nx.dev/docs/guides/adopting-nx/preserving-git-histories
Read the nx docs if you have the tools for it.
Import Strategy
Subdirectory-at-a-time (nx import <source> apps --source=apps):
- Recommended for monorepo sources — files land at top level, no redundant config
- Caveats: multiple import commands (separate merge commits each); dest must not have conflicting directories; root configs (deps, plugins, targetDefaults) not imported
- Directory conflicts: Import into alternate-named dir (e.g.
imported-apps/), then rename
Whole repo (nx import <source> imported --source=.):
- Only for non-monorepo sources (single-project repos)
- For monorepos, creates messy nested config (
imported/nx.json,imported/tsconfig.base.json, etc.) - If you must: keep imported
tsconfig.base.json(projects extend it), prefix workspace globs and executor paths
Directory Conventions
- Always prefer the destination's existing conventions. Source uses
libs/but dest usespackages/? Import intopackages/(nx import <source> packages/foo --source=libs/foo). - If dest has no convention (empty workspace), ask the user.
Application vs Library Detection
Before importing, identify whether the source is an application or a library:
- Applications: Deployable end products. Common indicators:
- _Frontend_:
next.config.*,vite.config.*with a build entry point, framework-specific app scaffolding (CRA, Angular CLI app, etc.) - _Backend (Node.js)_: Express/Fastify/NestJS server entrypoint, no
"exports"field inpackage.json - _JVM_: Maven
pom.xmlwith<packaging>jar</packaging>or<packaging>war</packaging>and amainclass; Gradleapplicationplugin ormainClasssetting - _.NET_:
.csproj/.fsprojwith<OutputType>Exe</OutputType>or<OutputType>WinExe</OutputType> - _General_: Dockerfile, a runnable entrypoint, no public API surface intended for import by other projects
- Libraries: Reusable packages consumed by other projects. Common indicators:
"main"/"exports"inpackage.json, Maven/Gradle packaging as a library jar, .NET<OutputType>Library</OutputType>, named exports intended for import by other packages.
Destination directory rules:
- Applications →
apps/<name>. Check workspace globs (e.g.pnpm-workspace.yaml,workspacesin rootpackage.json) for an existingapps/*entry. - If
apps/*is not present, add it before importing: update the workspace glob config and commit (or stage) the change. - Example:
nx import <source> apps/my-app --source=packages/my-app - Libraries → follow the dest's existing convention (
packages/,libs/, etc.).
Common Issues
pnpm Workspace Globs (Critical)
nx import adds the imported directory itself (e.g. apps) to pnpm-workspace.yaml, NOT glob patterns for packages within it. Cross-package imports will fail with Cannot find module.
Fix: Replace with proper globs from the source config (e.g. apps/*, libs/shared/*), then pnpm install.
Root Dependencies and Config Not Imported (Critical)
nx import does NOT merge from the source's root:
dependencies/devDependenciesfrompackage.jsontargetDefaultsfromnx.json(e.g."@nx/esbuild:esbuild": { "dependsOn": ["^build"] }— critical for build ordering)namedInputsfromnx.json(e.g.productionexclusion patterns for test files)- Plugin configurations from
nx.json
Fix: Diff source and dest package.json + nx.json. Add missing deps, merge relevant targetDefaults and namedInputs.
TypeScript Project References
After import, run nx sync --yes. If it reports nothing but typecheck still fails, nx reset first, then nx sync --yes again.
Explicit Executor Path Fixups
Inferred targets (via Nx plugins) resolve config relative to project root — no changes needed. Explicit executor targets (e.g. @nx/esbuild:esbuild) have workspace-root-relative paths (main, outputPath, tsConfig, assets, sourceRoot) that must be prefixed with the import destination directory.
Plugin Detection
- Whole-repo import:
nx importdetects and offers to install plugins. Accept them. - Subdirectory import: Plugins NOT auto-detected. Manually add with
npx nx add @nx/PLUGIN. Checkinclude/excludepatterns — defaults won't match alternate directories (e.g.apps-beta/). - Run
npx nx resetafter any plugin config changes.
Redundant Root Files (Whole-Repo Only)
Whole-repo import brings ALL source root files into the dest subdirectory. Clean up:
pnpm-lock.yaml— stale; dest has its own lockfilepnpm-workspace.yaml— source workspace config; conflicts with destnode_modules/— stale symlinks pointing to source filesystem.gitignore— redundant with dest root.gitignorenx.json— source Nx config; dest has its ownREADME.md— optional; keep or remove
Don't blindly delete tsconfig.base.json — imported projects may extend it via relative paths.
Root ESLint Config Missing (Subdirectory Import)
Subdirectory import doesn't bring the source's root eslint.config.mjs, but project configs reference ../../eslint.config.mjs.
Fix order:
1. Install ESLint deps first: pnpm add -wD eslint@^9 @nx/eslint-plugin typescript-eslint (plus framework-specific plugins) 2. Create root eslint.config.mjs (copy from source or create with @nx/eslint-plugin base rules) 3. Then npx nx add @nx/eslint to register the plugin in nx.json
Install typescript-eslint explicitly — pnpm's strict hoisting won't auto-resolve this transitive dep of @nx/eslint-plugin.
ESLint Version Pinning (Critical)
Pin ESLint to v9 (eslint@^9.0.0). ESLint 10 breaks @nx/eslint and many plugins with cryptic errors like Cannot read properties of undefined (reading 'version').
@nx/eslint may peer-depend on ESLint 8, causing the wrong version to resolve. If lint fails with Cannot read properties of undefined (reading 'allow'), add pnpm.overrides:
{ "pnpm": { "overrides": { "eslint": "^9.0.0" } } }Dependency Version Conflicts
After import, compare key deps (typescript, eslint, framework-specific). If dest uses newer versions, upgrade imported packages to match (usually safe). If source is newer, may need to upgrade dest first. Use pnpm.overrides to enforce single-version policy if desired.
Module Boundaries
Imported projects may lack tags. Add tags or update @nx/enforce-module-boundaries rules.
Project Name Collisions (Multi-Import)
Same name in package.json across source and dest causes MultipleProjectsWithSameNameError. Fix: Rename conflicting names (e.g. @org/api → @org/teama-api), update all dep references and import statements, pnpm install. The root package.json of each imported repo also becomes a project — rename those too.
Workspace Dep Import Ordering
pnpm install fails during nx import if a "workspace:*" dependency hasn't been imported yet. File operations still succeed. Fix: Import all projects first, then pnpm install --no-frozen-lockfile.
.gitkeep Blocking Subdirectory Import
The TS preset creates packages/.gitkeep. Remove it and commit before importing.
Frontend tsconfig Base Settings (Critical)
The TS preset defaults (module: "nodenext", moduleResolution: "nodenext", lib: ["es2022"]) are incompatible with frontend frameworks (React, Next.js, Vue, Vite). After importing frontend projects, verify the dest root tsconfig.base.json:
- `moduleResolution`: Must be
"bundler"(not"nodenext") - `module`: Must be
"esnext"(not"nodenext") - `lib`: Must include
"dom"and"dom.iterable"(frontend projects need these) - `jsx`:
"react-jsx"for React-only workspaces, per-project for mixed frameworks
For subdirectory imports, the dest root tsconfig is authoritative — update it. For whole-repo imports, imported projects may extend their own nested tsconfig.base.json, making this less critical.
If the dest also has backend projects needing nodenext, use per-project overrides instead of changing the root.
Gotcha: TypeScript does NOT merge lib arrays — a project-level override replaces the base array entirely. Always include all needed entries (e.g. es2022, dom, dom.iterable) in any project-level lib.
@nx/react Typings for Libraries
React libraries generated with @nx/react:library reference @nx/react/typings/cssmodule.d.ts and @nx/react/typings/image.d.ts in their tsconfig types. These fail with Cannot find type definition file unless @nx/react is installed in the dest workspace.
Fix: pnpm add -wD @nx/react
Jest Preset Missing (Subdirectory Import)
Nx presets create jest.preset.js at the workspace root, and project jest configs reference it (e.g. ../../jest.preset.js). Subdirectory import does NOT bring this file.
Fix:
1. Run npx nx add @nx/jest — registers @nx/jest/plugin in nx.json and updates namedInputs 2. Create jest.preset.js at workspace root (see references/JEST.md for content) — nx add only creates this when a generator runs, not on bare nx add 3. Install test runner deps: pnpm add -wD jest jest-environment-jsdom ts-jest @types/jest 4. Install framework-specific test deps as needed (see references/JEST.md)
For deeper Jest issues (tsconfig.spec.json, Babel transforms, CI atomization, Jest vs Vitest coexistence), see references/JEST.md.
Target Name Prefixing (Whole-Repo Import)
When importing a project with existing npm scripts (build, dev, start, lint), Nx plugins auto-prefix inferred target names to avoid conflicts: e.g. next:build, vite:build, eslint:lint.
Fix: Remove the Nx-rewritten npm scripts from the imported package.json, then either:
- Accept the prefixed names (e.g.
nx run app:next:build) - Rename plugin target names in
nx.jsonto use unprefixed names
Non-Nx Source Issues
When the source is a plain pnpm/npm workspace without nx.json.
npm Script Rewriting (Critical)
Nx rewrites package.json scripts during init, creating broken commands (e.g. vitest run → nx test run). Fix: Remove all rewritten scripts — Nx plugins infer targets from config files.
noEmit → composite + emitDeclarationOnly (Critical)
Plain TS projects use "noEmit": true, incompatible with Nx project references.
Symptoms: "typecheck target is disabled because one or more project references set 'noEmit: true'" or TS6310.
Fix in all imported tsconfigs:
1. Remove "noEmit": true. If inherited via extends chain, set "noEmit": false explicitly. 2. Add "composite": true, "emitDeclarationOnly": true, "declarationMap": true 3. Add "outDir": "dist" and "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo" 4. Add "extends": "../../tsconfig.base.json" if missing. Remove settings now inherited from base.
Stale node_modules and Lockfiles
nx import may bring node_modules/ (pnpm symlinks pointing to the source filesystem) and pnpm-lock.yaml from the source. Both are stale.
Fix: rm -rf imported/node_modules imported/pnpm-lock.yaml imported/pnpm-workspace.yaml imported/.gitignore, then pnpm install.
ESLint Config Handling
- Legacy `.eslintrc.json` (ESLint 8): Delete all
.eslintrc.*, remove v8 deps, create flateslint.config.mjs. - Flat config (`eslint.config.js`): Self-contained configs can often be left as-is.
- No ESLint: Create both root and project-level configs from scratch.
TypeScript paths Aliases
Nx uses package.json "exports" + pnpm workspace linking instead of tsconfig "paths". If packages have proper "exports", paths are redundant. Otherwise, update paths for the new directory structure.
Technology-specific Guidance
Identify technologies in the source repo, then read and apply the matching reference file(s).
Available references:
references/ESLINT.md— ESLint projects: duplicatelint/eslint:linttargets, legacy.eslintrc.*linting generated files, flat config.cjsself-linting,typescript-eslintv7/v9 peer dep conflict, mixed ESLint v8+v9 in one workspace.references/GRADLE.mdreferences/JEST.md— Jest testing:@nx/jest/pluginsetup, jest.preset.js, testing deps by framework, tsconfig.spec.json, Jest vs Vitest coexistence, Babel transforms, CI atomization.references/NEXT.md— Next.js projects:@nx/next/plugintargets,withNx, Next.js TS config (noEmit,jsx: "preserve"), auto-installing deps via wrong PM, non-Nxcreate-next-appimports, mixed Next.js+Vite coexistence.references/TURBOREPO.mdreferences/VITE.md— Vite projects (React, Vue, or both):@nx/vite/plugintypecheck target,resolve.alias/__dirnamefixes, framework deps, Vue-specific setup, mixed React+Vue coexistence.
ESLint
ESLint-specific guidance for nx import. For generic import issues (root deps, pnpm globs, project references), see SKILL.md.
---
How @nx/eslint/plugin Works
@nx/eslint/plugin scans for ESLint config files and creates a lint target for each project. It detects both flat config files (eslint.config.{js,mjs,cjs,ts,mts,cts}) and legacy config files (.eslintrc.{json,js,cjs,mjs,yml,yaml}).
Plugin options (set during `nx add @nx/eslint`):
{
"plugin": "@nx/eslint/plugin",
"options": {
"targetName": "eslint:lint"
}
}Auto-installation: nx import auto-detects ESLint config files and offers to install @nx/eslint. Accept the offer — it registers the plugin and updates namedInputs.production to exclude ESLint config files.
---
Duplicate lint and eslint:lint Targets
After import, projects will have two lint-related targets if the source package.json has a "lint" npm script:
eslint:lint— inferred by@nx/eslint/plugin; has proper caching and input/output trackinglint— created by Nx from the npm script vianx:run-script; no caching intelligence, just wrapsnpm run lint
Fix: Remove the "lint" script from each project's package.json. Keep "lint:fix" if present — there is no plugin-inferred equivalent for auto-fixing.
---
Legacy .eslintrc.* Configs Linting Generated Files
When @nx/eslint/plugin runs eslint . on a project with a legacy .eslintrc.* config that uses parserOptions.project, it tries to lint all files in the project directory including:
- Generated
dist/**/*.d.tsfiles (not in tsconfiginclude) - The
.eslintrc.jsconfig file itself (not in tsconfiginclude)
This causes Parsing error: ESLint was configured to run on X using parserOptions.project, however that TSConfig does not include this file.
Fix: Add ignorePatterns to the .eslintrc.* config:
// .eslintrc.json
{
"ignorePatterns": ["dist/**"]
}// .eslintrc.js — also ignore the config file itself since module.exports isn't in tsconfig
module.exports = {
ignorePatterns: ['dist/**', '.eslintrc.js'],
// ...
};---
Flat Config .cjs Files Self-Linting
When a project uses eslint.config.cjs (CJS flat config), eslint . lints the config file itself. The require() call on line 1 triggers @typescript-eslint/no-require-imports.
Fix: Add the config filename to the top-level ignores array:
module.exports = tseslint.config(
{
ignores: ['dist/**', 'node_modules/**', 'eslint.config.cjs'],
}
// ...
);The same applies to eslint.config.js in a CJS project (no "type": "module") if it uses require().
---
typescript-eslint Version Conflict With ESLint 9
typescript-eslint@7.x declares peerDependencies: { "eslint": "^8.56.0" }, but it is commonly used alongside "eslint": "^9.0.0". npm treats this as a hard peer dep conflict and refuses to install.
Root cause: @nx/eslint init adds eslint@~8.57.0 at the workspace root (for its own peer deps). Workspace packages that request eslint@^9.0.0 + typescript-eslint@^7.0.0 trigger the conflict when npm resolves their deps.
Fix: Upgrade typescript-eslint from ^7.0.0 to ^8.0.0 directly in the affected workspace package's package.json. The tseslint.config() API and tseslint.configs.recommended are identical between v7 and v8 — no config changes needed.
// packages/my-package/package.json
{
"devDependencies": {
"typescript-eslint": "^8.0.0"
}
}Note: npm's root-level "overrides" field does not force versions for workspace packages' direct dependencies — update each package.json individually.
---
Mixed ESLint v8 and v9 in One Workspace
Legacy v8 and flat-config v9 packages can coexist in the same workspace. Each package resolves its own eslint version. The root eslint@~8.57.0 (added by @nx/eslint init) is used by legacy v8 packages; v9 packages get their own hoisted eslint@9.
@nx/eslint/plugin infers eslint:lint targets for both config formats. Legacy packages run ESLint v8 with .eslintrc.*; flat-config packages run ESLint v9 with eslint.config.*. No special nx.json configuration is needed to support both simultaneously.
Gradle
- If you import an entire Gradle repository into a subfolder, files like
gradlew,gradlew.bat, andgradle/wrapperwill end up inside that imported subfolder. - The
@nx/gradleplugin expects those files at the workspace root to infer Gradle projects/tasks automatically. - If the target workspace has no Gradle setup yet, consider moving those files to the root (especially when using
@nx/gradle). - If the target workspace already has Gradle configured, avoid duplicate wrappers: remove imported duplicates from the subfolder or merge carefully.
- Because the import lands in a subfolder, Gradle project references can break; review settings and project path references, then fix any errors.
- If
@nx/gradleis installed, runnx show projectsto verify that Gradle projects are being inferred.
Helpful docs:
- https://nx.dev/docs/technologies/java/gradle/introduction
Jest
Jest-specific guidance for nx import. For the basic "Jest Preset Missing" fix (create jest.preset.js, install deps), see SKILL.md. This file covers deeper Jest integration issues.
---
How @nx/jest Works
@nx/jest/plugin scans for jest.config.{ts,js,cjs,mjs,cts,mts} and creates a test target for each project.
Plugin options:
{
"plugin": "@nx/jest/plugin",
"options": {
"targetName": "test"
}
}npx nx add @nx/jest does two things:
1. Registers `@nx/jest/plugin` in `nx.json` — without this, no test targets are inferred 2. Updates namedInputs.production to exclude test files
Gotcha: nx add @nx/jest does NOT create jest.preset.js — that file is only generated when you run a generator (e.g. @nx/jest:configuration). For imports, you must create it manually (see "Jest Preset" section below).
Other gotcha: If you create jest.preset.js manually but skip npx nx add @nx/jest, the plugin won't be registered and nx run PROJECT:test will fail with "Cannot find target 'test'". You need both.
---
Jest Preset
The preset provides shared Jest configuration (test patterns, ts-jest transform, resolver, jsdom environment).
Root `jest.preset.js`:
const nxPreset = require('@nx/jest/preset').default;
module.exports = { ...nxPreset };Project `jest.config.ts`:
export default {
displayName: 'my-lib',
preset: '../../jest.preset.js',
// project-specific overrides
};The preset path is relative from the project root to the workspace root. Subdirectory imports preserve the original relative path (e.g. ../../jest.preset.js), which resolves correctly if the import destination matches the source directory depth.
---
Testing Dependencies
Core (always needed)
pnpm add -wD jest ts-jest @types/jest @nx/jestEnvironment-specific
- DOM testing (React, Vue, browser libs):
jest-environment-jsdom - Node testing (APIs, CLIs): no extra deps (Jest defaults to
nodeenv, but Nx preset defaults tojsdom)
React testing
pnpm add -wD @testing-library/react @testing-library/jest-domReact with Babel (non-ts-jest transform)
Some React projects use Babel instead of ts-jest for JSX transformation:
pnpm add -wD babel-jest @babel/core @babel/preset-env @babel/preset-react @babel/preset-typescriptWhen: Project jest.config has transform using babel-jest instead of ts-jest. Common in older Nx workspaces and CRA migrations.
Vue testing
pnpm add -wD @vue/test-utilsVue projects typically use Vitest (not Jest) — see VITE.md.
---
tsconfig.spec.json
Jest projects need a tsconfig.spec.json that includes test files:
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"]
},
"include": [
"jest.config.ts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.d.ts"
]
}Common issues after import:
- Missing
"types": ["jest", "node"]— causesdescribe/it/expectto be unrecognized - Missing
"module": "commonjs"— Jest doesn't support ESM by default (ts-jest transpiles to CJS) includearray missing test patterns — TypeScript won't check test files
---
Jest vs Vitest Coexistence
Workspaces can have both:
- Jest: Next.js apps, older React libs, Node libraries
- Vitest: Vite-based React/Vue apps and libs
Both @nx/jest/plugin and @nx/vite/plugin (which infers Vitest targets) coexist without conflicts — they detect different config files (jest.config.* vs vite.config.*).
Target naming: Both default to test. If a project somehow has both config files, rename one:
{
"plugin": "@nx/jest/plugin",
"options": { "targetName": "jest-test" }
}---
@testing-library/jest-dom — Jest vs Vitest
Projects migrating from Jest to Vitest (or workspaces with both) need different imports:
Jest (in test-setup.ts):
import '@testing-library/jest-dom';Vitest (in test-setup.ts):
import '@testing-library/jest-dom/vitest';If the source used Jest but the dest workspace uses Vitest for that project type, update the import path. Also add @testing-library/jest-dom to tsconfig types array.
---
Non-Nx Source: Test Script Rewriting
Nx rewrites package.json scripts during init. Test scripts get broken:
"test": "jest"→"test": "nx test"(circular if no executor configured)"test": "vitest run"→"test": "nx test run"(broken —runbecomes an argument)
Fix: Remove all rewritten test scripts. @nx/jest/plugin and @nx/vite/plugin infer test targets from config files.
---
CI Atomization
@nx/jest/plugin supports splitting tests per-file for CI parallelism:
{
"plugin": "@nx/jest/plugin",
"options": {
"targetName": "test",
"ciTargetName": "test-ci"
}
}This creates test-ci--src/lib/foo.spec.ts targets for each test file, enabling Nx Cloud distribution. Not relevant during import, but useful for post-import CI setup.
---
Common Post-Import Issues
1. "Cannot find target 'test'": @nx/jest/plugin not registered in nx.json. Run npx nx add @nx/jest or manually add the plugin entry.
2. "Cannot find module 'jest-preset'": jest.preset.js missing at workspace root. Create it (see SKILL.md).
3. "Cannot find type definition file for 'jest'": Missing @types/jest or tsconfig.spec.json doesn't have "types": ["jest", "node"].
4. Tests fail with "Cannot use import statement outside a module": ts-jest not installed or not configured as transform. Check jest.config.ts transform section.
5. Snapshot path mismatches: After import, __snapshots__ directories may have paths baked in. Run tests once with --updateSnapshot to regenerate.
---
Fix Order
Subdirectory Import (Nx Source)
1. npx nx add @nx/jest — registers plugin in nx.json (does NOT create jest.preset.js) 2. Create jest.preset.js manually (see "Jest Preset" section above) 3. Install deps: pnpm add -wD jest jest-environment-jsdom ts-jest @types/jest 4. Install framework test deps: @testing-library/react @testing-library/jest-dom (React), @vue/test-utils (Vue) 5. Verify tsconfig.spec.json has "types": ["jest", "node"] 6. nx run-many -t test
Whole-Repo Import (Non-Nx Source)
1. Remove rewritten test scripts from package.json 2. npx nx add @nx/jest — registers plugin (does NOT create preset) 3. Create jest.preset.js manually 4. Install deps (same as above) 5. Verify/fix jest.config.* — ensure preset path points to root jest.preset.js 6. Verify/fix tsconfig.spec.json — add types, module, include if missing 7. nx run-many -t test
Next.js
Next.js-specific guidance for nx import. For generic import issues (pnpm globs, root deps, project references, name collisions, ESLint, frontend tsconfig base settings, @nx/react typings, Jest preset, target name prefixing, non-Nx source handling), see SKILL.md.
---
@nx/next/plugin Inferred Targets
@nx/next/plugin detects next.config.{ts,js,cjs,mjs} and creates these targets:
build→next build(withdependsOn: ['^build'])dev→next devstart→next start(depends onbuild)serve-static→ same asstartbuild-deps/watch-deps— for TS solution setup
No separate typecheck target — Next.js runs TypeScript checking as part of next build. The @nx/js/typescript plugin provides a standalone typecheck target for non-Next libraries in the workspace.
Build target conflict: Both @nx/next/plugin and @nx/js/typescript define a build target. @nx/next/plugin wins for Next.js projects (it detects next.config.*), while @nx/js/typescript handles libraries with tsconfig.lib.json. No rename needed — they coexist.
withNx in next.config.js
Nx-generated Next.js projects use composePlugins(withNx) from @nx/next. This wrapper is optional for next build via the inferred plugin (which just runs next build), but it provides Nx-specific configuration. Keep it if present.
Root Dependencies for Next.js
Beyond the generic root deps issue (see SKILL.md), Next.js projects typically need:
Core: react, react-dom, @types/react, @types/react-dom, @types/node, @nx/react (see SKILL.md for @nx/react typings) Nx plugins: @nx/next (auto-installed by import), @nx/eslint, @nx/jest Testing: see SKILL.md "Jest Preset Missing" section ESLint: @next/eslint-plugin-next (in addition to generic ESLint deps from SKILL.md)
Next.js Auto-Installing Dependencies via Wrong Package Manager
Next.js detects missing @types/react during next build and tries to install it using yarn add regardless of the actual package manager. In a pnpm workspace, this fails with a "nearest package directory isn't part of the project" error.
Root cause: @types/react is missing from root devDependencies. Fix: Install deps at the root before building: pnpm add -wD @types/react @types/react-dom
Next.js TypeScript Config Specifics
Next.js app tsconfigs have unique patterns compared to Vite:
- `noEmit: true` with
emitDeclarationOnly: false— Next.js handles emit, TS just checks types. This conflicts withcomposite: truefrom the TS solution setup. - `"types": ["jest", "node"]` — includes test types in the main tsconfig (no separate
tsconfig.app.json) - `"plugins": [{ "name": "next" }]` — for IDE integration
- `include` references
.next/types/**/*.tsfor Next.js auto-generated types - `"jsx": "preserve"` — Next.js uses its own JSX transform, not React's
Gotcha: The Next.js tsconfig sets "noEmit": true which disables composite mode. This is fine because Next.js projects use next build for building, not tsc. The @nx/js/typescript plugin's typecheck target is not needed for Next.js apps.
next.config.js Lint Warning
Imported Next.js configs may have // eslint-disable-next-line @typescript-eslint/no-var-requires but the project ESLint config enables different rule sets. This produces Unused eslint-disable directive warnings. Harmless — remove the comment or ignore.
@nx/next:init Rewrites All npm Scripts (Whole-Repo Import)
When @nx/next:init runs during a whole-repo import, it rewrites the project's package.json scripts to prefixed nx calls:
{
"dev": "nx next:dev",
"build": "nx next:build",
"start": "nx next:start"
}This is the standard "npm Script Rewriting" issue from SKILL.md, but triggered by @nx/next:init rather than Nx init. Fix: Remove all rewritten scripts from package.json — @nx/next/plugin infers all targets from next.config.*.
---
Non-Nx Source (create-next-app)
Whole-Repo Import Recommended
For single-project create-next-app repos, use whole-repo import into a subdirectory:
nx import /path/to/source apps/web --ref=main --source=. --no-interactivenext-env.d.ts
next build auto-generates next-env.d.ts at the project root. Add next-env.d.ts to the dest root .gitignore — it is framework-generated and should not be committed.
ESLint: Self-Contained eslint-config-next
create-next-app generates a flat ESLint config using eslint-config-next (which bundles its own plugins). This is self-contained — no root eslint.config.mjs needed, no @nx/eslint-plugin dependency. The @nx/eslint/plugin detects it and creates a lint target.
TypeScript: No Changes Needed
Non-Nx Next.js projects have self-contained tsconfigs with noEmit: true, their own lib, module, moduleResolution, and jsx settings. Since next build handles type checking internally, no tsconfig modifications are needed. The project does NOT need to extend tsconfig.base.json.
Gotcha: The @nx/js/typescript plugin won't create a typecheck target because there's no tsconfig.lib.json. This is fine — use next:build for type checking.
noEmit: true and TS Solution Setup
Non-Nx Next.js projects use noEmit: true, which conflicts with Nx's TS solution setup (composite: true). If the dest workspace uses project references and you want the Next.js app to participate:
1. Remove noEmit: true, add composite: true, emitDeclarationOnly: true 2. Add extends: "../../tsconfig.base.json" 3. Add outDir and tsBuildInfoFile
However, this is optional for standalone Next.js apps that don't export types consumed by other workspace projects.
Tailwind / PostCSS
create-next-app with Tailwind generates postcss.config.mjs. This works as-is after import — no path changes needed since PostCSS resolves relative to the project root.
---
Mixed Next.js + Vite Coexistence
When both Next.js and Vite projects exist in the same workspace.
Plugin Coexistence
Both @nx/next/plugin and @nx/vite/plugin can coexist in nx.json. They detect different config files (next.config.* vs vite.config.*) so there are no conflicts. The @nx/js/typescript plugin handles libraries.
Vite Standalone Project tsconfig Fixes
Vite standalone projects (imported as whole-repo) have self-contained tsconfigs without composite: true. The @nx/js/typescript plugin's typecheck target runs tsc --build --emitDeclarationOnly which requires composite.
Fix:
1. Add extends: "../../tsconfig.base.json" to the root project tsconfig 2. Add composite: true, declaration: true, declarationMap: true, tsBuildInfoFile to tsconfig.app.json and tsconfig.spec.json 3. Set moduleResolution: "bundler" (replace "node") 4. Add source files to tsconfig.spec.json include — specs import app code, and composite mode requires all files to be listed
Typecheck Target Names
@nx/vite/plugindefaultstypecheckTargetNameto"vite:typecheck"@nx/js/typescriptuses"typecheck"- Next.js projects have NO standalone typecheck target — Next.js runs type checking during
next build
No naming conflicts between frameworks.
---
Fix Order — Nx Source (Subdirectory Import)
1. Import Next.js apps into apps/<name> (see SKILL.md: "Application vs Library Detection") 2. Generic fixes from SKILL.md (pnpm globs, root deps, .gitkeep removal, frontend tsconfig base settings, @nx/react typings) 3. Install Next.js-specific deps: pnpm add -wD @next/eslint-plugin-next 4. ESLint setup (see SKILL.md: "Root ESLint Config Missing") 5. Jest setup (see SKILL.md: "Jest Preset Missing") 6. nx reset && nx sync --yes && nx run-many -t typecheck,build,test,lint
Fix Order — Non-Nx Source (create-next-app)
1. Import into apps/<name> (see SKILL.md: "Application vs Library Detection") 2. Generic fixes from SKILL.md (pnpm globs, stale files cleanup, script rewriting, target name prefixing) 3. (Optional) If app needs to export types for other workspace projects: fix noEmit → composite (see SKILL.md) 4. nx reset && nx run-many -t next:build,eslint:lint (or unprefixed names if renamed)
---
Iteration Log
Scenario 1: Basic Nx Next.js App Router + Shared Lib → TS preset (PASS)
- Source: CNW next preset (Next.js 16, App Router) +
@nx/react:libraryshared-ui - Dest: CNW ts preset (Nx 23)
- Import: subdirectory-at-a-time (apps, libs separately)
- Errors found & fixed:
1. pnpm-workspace.yaml: apps/libs → apps/*/libs/* 2. Root tsconfig: nodenext → bundler, add dom/dom.iterable to lib, add jsx: react-jsx 3. Missing @nx/react (for CSS module/image type defs in lib) 4. Missing @types/react, @types/react-dom, @types/node 5. Next.js trying yarn add @types/react — fixed by installing at root 6. Missing @nx/eslint, root eslint.config.mjs, ESLint plugins 7. Missing @nx/jest, jest.preset.js, jest-environment-jsdom, ts-jest
- All targets green: typecheck, build, test, lint
Scenario 3: Non-Nx create-next-app (App Router + Tailwind) → TS preset (PASS)
- Source:
create-next-app@latest(Next.js 16.1.6, App Router, Tailwind v4, flat ESLint config) - Dest: CNW ts preset (Nx 23)
- Import: whole-repo into
apps/web - Errors found & fixed:
1. pnpm-workspace.yaml: apps/web → apps/* 2. Stale files: node_modules/, pnpm-lock.yaml, pnpm-workspace.yaml, .gitignore — deleted 3. Nx-rewritten npm scripts ("build": "nx next:build", etc.) — removed
- No tsconfig changes needed — self-contained config with
noEmit: true - ESLint self-contained via
eslint-config-next— no root config needed - No test setup (create-next-app doesn't include tests)
- All targets green: next:build, eslint:lint
Scenario 4: Non-Nx create-next-app (alongside Vite, React Router 7, TanStack, CRA) → TS preset (PASS)
- See VITE.md Scenario 6 for the full multi-import scenario
- Next.js-specific findings:
1. @nx/next:init rewrote all scripts to nx next:* format — removed all rewritten scripts 2. Stale files: node_modules/, package-lock.json, .gitignore — deleted (npm workspace, no pnpm files) 3. ESLint self-contained via eslint-config-next — no root config needed 4. No tsconfig changes needed — noEmit: true stays; next build handles type checking
- Targets:
next:build,next:dev,next:start,eslint:lint
Scenario 5: Mixed Next.js (Nx) + Vite React (standalone) → TS preset (PASS)
- Source A: CNW next preset (Next.js 16, App Router) — subdirectory import of
apps/ - Source B: CNW react-standalone preset (Vite 7, React 19) — whole-repo import into
apps/vite-app - Dest: CNW ts preset (Nx 23)
- Errors found & fixed:
1. All Scenario 1 fixes for the Next.js app 2. Stale files from Vite source: node_modules/, pnpm-lock.yaml, pnpm-workspace.yaml, .gitignore, nx.json 3. Removed rewritten scripts from Vite app's package.json 4. ESLint 8 vs 9 conflict — @nx/eslint peer on ESLint 8 resolved wrong version. Fixed with pnpm.overrides 5. Vite tsconfigs missing composite: true, declaration: true — needed for tsc --build --emitDeclarationOnly 6. Vite tsconfig.spec.json include missing source files — specs import app code 7. Vite tsconfig moduleResolution: "node" → "bundler", added extends: "../../tsconfig.base.json"
- All targets green: typecheck, build, test, lint for both projects
Turborepo
- Nx replaces Turborepo task orchestration, but a clean migration requires handling Turborepo's config packages.
- Migration guide: https://nx.dev/docs/guides/adopting-nx/from-turborepo#easy-automated-migration-example
- Since Nx replaces Turborepo, all turbo config files and config packages become dead code and should be removed.
The Config-as-Package Pattern
Turborepo monorepos ship with internal workspace packages that share configuration:
- `@repo/typescript-config` (or similar) — tsconfig files (
base.json,nextjs.json,react-library.json, etc.) - `@repo/eslint-config` (or similar) — ESLint config files and all ESLint plugin dependencies
These are not code libraries. They distribute config via Node module resolution (e.g., "extends": "@repo/typescript-config/nextjs.json"). This is the default Turborepo pattern — expect it in virtually every Turborepo import. Package names vary — check package.json files to identify the actual names.
Check for Root Config Files First
Before doing any config merging, check whether the destination workspace uses shared root configuration. This decides how to handle the config packages.
- If the workspace has a root
tsconfig.base.jsonand/or rooteslint.config.mjsthat projects extend, merge the config packages into these root configs (see steps below). - If the workspace does NOT have root config files — each project manages its own configuration independently (similar to Turborepo). In this case, do not create root config files or merge into them. Just remove turbo-specific parts (
turbo.json,eslint-plugin-turbo) and leave the config packages in place, or ask the user how they want to handle them.
If unclear, check for the presence of tsconfig.base.json at the root or ask the user.
Merging TypeScript Config (Only When Root tsconfig.base.json Exists)
The config package contains a hierarchy of tsconfig files. Each project extends one via package name.
1. Read the config package — trace the full inheritance chain (e.g., nextjs.json extends base.json). 2. Update root `tsconfig.base.json` — absorb compilerOptions from the base config. Add Nx paths for cross-project imports (Turborepo doesn't use path aliases, Nx relies on them). 3. Update each project's `tsconfig.json`:
- Change
"extends"from"@repo/typescript-config/<variant>.json"to the relative path to roottsconfig.base.json. - Inline variant-specific overrides from the intermediate config (e.g., Next.js:
"module": "ESNext","moduleResolution": "Bundler","jsx": "preserve","noEmit": true; React library:"jsx": "react-jsx"). - Preserve project-specific settings (
outDir,include,exclude, etc.).
4. Delete the config package and remove it from all devDependencies.
Merging ESLint Config (Only When Root eslint.config Exists)
The config package centralizes ESLint plugin dependencies and exports composable flat configs.
1. Read the config package — identify exported configs, plugin dependencies, and inheritance. 2. Update root `eslint.config.mjs` — absorb base rules (JS recommended, TypeScript-ESLint, Prettier, etc.). Drop eslint-plugin-turbo. 3. Update each project's `eslint.config.mjs` — switch from importing @repo/eslint-config/<variant> to extending the root config, adding framework-specific plugins inline. 4. Move ESLint plugin dependencies from the config package to root devDependencies. 5. If @nx/eslint plugin is configured with inferred targets, remove "lint" scripts from project package.json files. 6. Delete the config package and remove it from all devDependencies.
General Cleanup
- Remove turbo-specific dependencies:
turbo,eslint-plugin-turbo. - Delete all
turbo.jsonfiles (root and per-package). - Run workspace validation (
nx run-many -t build lint test typecheck) to confirm nothing broke.
Key Pitfalls
- Trace the full inheritance chain before inlining — check what each variant inherits from the base.
- Module resolution changes — from Node package resolution (
@repo/...) to relative paths (../../tsconfig.base.json). - ESLint configs are JavaScript, not JSON — handle JS imports, array spreading, and plugin objects when merging.
Helpful docs:
- https://nx.dev/docs/guides/adopting-nx/from-turborepo
Vite
Vite-specific guidance for nx import. For generic import issues (pnpm globs, root deps, project references, name collisions, ESLint, frontend tsconfig base settings, @nx/react typings, Jest preset, non-Nx source handling), see SKILL.md.
---
@nx/vite/plugin Typecheck Target
@nx/vite/plugin defaults typecheckTargetName to "vite:typecheck". If the workspace expects "typecheck", set it explicitly in nx.json. If @nx/js/typescript is also registered, rename one target to avoid conflicts (e.g. "tsc-typecheck" for the JS plugin).
Keep both plugins only if the workspace has non-Vite pure TS libraries — @nx/js/typescript handles those while @nx/vite/plugin handles Vite projects.
@nx/vite Plugin Install Failure
Plugin init loads vite.config.ts before deps are available. Fix: pnpm add -wD vite @vitejs/plugin-react (or @vitejs/plugin-vue) first, then pnpm exec nx add @nx/vite.
Vite resolve.alias and __dirname (Non-Nx Sources)
`__dirname` undefined (CJS-only): Replace with fileURLToPath(new URL('./src', import.meta.url)) from 'node:url'.
`@/` path alias: Vite's resolve.alias works at runtime but TS needs matching "paths". Set "baseUrl": "." in project tsconfig.
PostCSS/Tailwind: Verify content globs resolve correctly after import.
Missing TypeScript types (Non-Nx Sources)
Non-Nx tsconfigs may not declare all needed types. Ensure Vite projects include "types": ["node", "vite/client"] in their tsconfig.
noEmit Fix: Vite-Specific Notes
See SKILL.md for the generic noEmit→composite fix. Vite-specific additions:
- Non-Nx Vite projects often have both
tsconfig.app.jsonandtsconfig.node.jsonwithnoEmit— fix both - Solution-style tsconfigs (
"files": [], "references": [...]) may lackextends. Addextendspointing to the dest roottsconfig.base.jsonso base settings (moduleResolution,lib) apply. - This is safe — Vite/Vitest ignore TypeScript emit settings.
Dependency Version Conflicts
Shared Vite deps (both frameworks): vite, vitest, jsdom, @types/node, typescript (dev)
Vite 6→7: Typecheck fails (Plugin<any> type mismatch); build/serve still works. Fix: align versions. Vitest 3→4: Usually works; type conflicts may surface in shared test utils.
---
React Router 7 (Vite-Based)
React Router 7 (@react-router/dev) uses Vite under the hood with a vite.config.ts and a react-router.config.ts. The @nx/vite/plugin detects vite.config.ts and creates inferred targets.
Targets
@nx/vite/plugin creates build, dev, serve targets. The build target invokes the script defined in package.json (usually react-router build), not vite build directly.
No separate typecheck target from `@nx/vite/plugin` — React Router 7 typegen is run as part of typecheck (e.g. react-router typegen && tsc). The typecheck target is inferred from the tsconfig. Keep the typecheck script in package.json if present; it is not rewritten.
tsconfig Notes
React Router 7 uses a single tsconfig.json (no tsconfig.app.json/tsconfig.node.json split). It includes:
"rootDirs": [".", "./.react-router/types"]— for generated type files; keep as-is"paths": { "~/*": ["./app/*"] }— self-referential alias; keep as-is"noEmit": true— replace with composite settings per SKILL.md
Build Output
React Router 7 outputs to build/ (not dist/). Add build to the dest root .gitignore.
Generated Types Directory
React Router 7 generates .react-router/ at the project root for route type generation. Add .react-router to the dest root .gitignore.
---
TanStack Start (Vite-Based)
TanStack Start uses Vinxi under the hood, which wraps Vite. Projects have a standard vite.config.ts that @nx/vite/plugin detects normally.
Targets
@nx/vite/plugin creates build, dev, preview, serve-static, typecheck targets. The build target runs vite build which invokes the TanStack Start Vinxi pipeline (produces both client and SSR bundles).
tsconfig Notes
TanStack Start uses a single tsconfig.json with "allowImportingTsExtensions": true and "noEmit": true. Apply the standard noEmit → composite fix. allowImportingTsExtensions is compatible with emitDeclarationOnly: true — no change needed.
paths Aliases
TanStack Start commonly uses "#/*": ["./src/*"] and "@/*": ["./src/*"]. These are self-referential — keep as-is for a single-project app.
Uncommitted Source Repo
create-tan-stack initializes a git repo but does NOT make an initial commit. Before importing, commit first:
git -C /path/to/source add . && git -C /path/to/source commit -m "Initial commit"Generated and Build Directories
TanStack Start / Vinxi / Nitro generate several directories that must be added to the dest root .gitignore:
.vinxi— Vinxi build cache.tanstack— TanStack generated files.nitro— Nitro build artifacts.output— server-side build output (SSR/edge)
These are not covered by dist or build.
---
React-Specific
React Dependencies
Production: react, react-dom Dev: @types/react, @types/react-dom, @vitejs/plugin-react, @testing-library/react, @testing-library/jest-dom, jsdom ESLint (Nx sources): eslint-plugin-import, eslint-plugin-jsx-a11y, eslint-plugin-react, eslint-plugin-react-hooks ESLint (`create-vite`): eslint-plugin-react-refresh, eslint-plugin-react-hooks — self-contained flat configs can be left as-is Nx plugins: @nx/react (generators), @nx/vite, @nx/vitest, @nx/eslint
React TypeScript Configuration
Add "jsx": "react-jsx" — in tsconfig.base.json for single-framework workspaces, per-project for mixed (see Mixed section).
React ESLint Config
import nx from '@nx/eslint-plugin';
import baseConfig from '../../eslint.config.mjs';
export default [
...baseConfig,
...nx.configs['flat/react'],
{ files: ['**/*.ts', '**/*.tsx'], rules: {} },
];React Version Conflicts
React 18 (source) + React 19 (dest): pnpm may hoist mismatched react-dom, causing TypeError: Cannot read properties of undefined (reading 'S'). Fix: Align versions with pnpm.overrides.
@testing-library/jest-dom with Vitest
If source used Jest: change import to @testing-library/jest-dom/vitest in test-setup.ts, add to tsconfig types.
---
Vue-Specific
Vue Dependencies
Production: vue (plus vue-router, pinia if used) Dev: @vitejs/plugin-vue, vue-tsc, @vue/test-utils, jsdom ESLint: eslint-plugin-vue, vue-eslint-parser, @vue/eslint-config-typescript, @vue/eslint-config-prettier Nx plugins: @nx/vue (generators), @nx/vite, @nx/vitest, @nx/eslint (install AFTER deps — see below)
Vue TypeScript Configuration
Add to tsconfig.base.json (single-framework) or per-project (mixed):
{ "jsx": "preserve", "jsxImportSource": "vue", "resolveJsonModule": true }vue-shims.d.ts
Vue SFC files need a type declaration. Usually exists in each project's src/ and imports cleanly. If missing:
declare module '*.vue' {
import { defineComponent } from 'vue';
const component: ReturnType<typeof defineComponent>;
export default component;
}vue-tsc Auto-Detection
Both @nx/js/typescript and @nx/vite/plugin auto-detect vue-tsc when installed — no manual config needed. Remove source scripts like "typecheck": "vue-tsc --noEmit".
ESLint Plugin Installation Order (Critical)
@nx/eslint init crashes if Vue ESLint deps aren't installed first (it loads all config files).
Correct order:
1. pnpm add -wD eslint@^9 eslint-plugin-vue vue-eslint-parser @vue/eslint-config-typescript @typescript-eslint/parser @nx/eslint-plugin typescript-eslint 2. Create root eslint.config.mjs 3. Then npx nx add @nx/eslint
Vue ESLint Config Pattern
import vue from 'eslint-plugin-vue';
import vueParser from 'vue-eslint-parser';
import tsParser from '@typescript-eslint/parser';
import baseConfig from '../../eslint.config.mjs';
export default [
...baseConfig,
...vue.configs['flat/recommended'],
{
files: ['**/*.vue'],
languageOptions: { parser: vueParser, parserOptions: { parser: tsParser } },
},
{
files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx', '**/*.vue'],
rules: { 'vue/multi-word-component-names': 'off' },
},
];Important: vue-eslint-parser override must come AFTER base config — flat/typescript sets the TS parser globally without a files filter, breaking .vue parsing.
vue-eslint-parser must be an explicit pnpm dependency (strict resolution prevents transitive import).
Known issue: Some generated Vue ESLint configs omit vue-eslint-parser. Use the pattern above instead.
---
Mixed React + Vue
When both frameworks coexist, several settings become per-project.
tsconfig jsx — Per-Project Only
- React:
"jsx": "react-jsx"in project tsconfig - Vue:
"jsx": "preserve","jsxImportSource": "vue"in project tsconfig - Root: NO
jsxsetting
Typecheck — Auto-Detects Framework
@nx/vite/plugin uses vue-tsc for Vue projects and tsc for React automatically.
{
"plugins": [
{ "plugin": "@nx/eslint/plugin", "options": { "targetName": "lint" } },
{
"plugin": "@nx/vite/plugin",
"options": {
"buildTargetName": "build",
"typecheckTargetName": "typecheck",
"testTargetName": "test"
}
}
]
}Remove @nx/js/typescript if all projects use Vite. Keep it (renamed to "tsc-typecheck") only for non-Vite pure TS libs.
ESLint — Three-Tier Config
1. Root: Base rules only, no framework-specific rules 2. React projects: Extend root + nx.configs['flat/react'] 3. Vue projects: Extend root + vue.configs['flat/recommended'] + vue-eslint-parser
Required packages: Shared (eslint@^9, @nx/eslint-plugin, typescript-eslint, @typescript-eslint/parser), React (eslint-plugin-import, eslint-plugin-jsx-a11y, eslint-plugin-react, eslint-plugin-react-hooks), Vue (eslint-plugin-vue, vue-eslint-parser)
@nx/react/@nx/vue are for generators only — no target conflicts.
---
Redundant npm Scripts After Import
nx import copies package.json verbatim, so npm scripts come along. For Vite-based projects @nx/vite/plugin already infers the same targets from vite.config.ts — the npm scripts just shadow the plugin with weaker nx:run-script wrappers (no first-class caching inputs/outputs). Remove them after import.
Standalone Vite App (create-vite)
Remove the following scripts — every one is redundant:
| Script | Plugin replacement |
|---|---|
dev: vite | @nx/vite/plugin → dev |
build: tsc -b && vite build | @nx/vite/plugin → build; typecheck via @nx/js/typescript handles tsc |
preview: vite preview | @nx/vite/plugin → preview |
lint: eslint . | @nx/eslint/plugin → eslint:lint |
TanStack Start
Remove build, dev, preview, and test scripts, but move any hardcoded --port flag to vite.config.ts first:
// vite.config.ts
export default defineConfig({
server: { port: 3000 }, // replaces `vite dev --port 3000`
...
})React Router 7 — Keep ALL scripts
Do not remove React Router 7 scripts. They use the framework CLI (react-router build, react-router dev, react-router-serve) which is not interchangeable with plain vite:
typecheckrunsreact-router typegen && tsc— typegen must precedetscor it fails on missing route typesstartserves the SSR bundle — no plugin equivalent
---
Fix Orders
Nx Source
1. Generic fixes from SKILL.md (pnpm globs, root deps, executor paths, frontend tsconfig base settings, @nx/react typings) 2. Configure @nx/vite/plugin typecheck target 3. React: jsx: "react-jsx" (root or per-project) 4. Vue: jsx: "preserve" + jsxImportSource: "vue"; verify vue-shims.d.ts; install ESLint deps before @nx/eslint 5. Mixed: jsx per-project; remove/rename @nx/js/typescript 6. nx sync --yes && nx reset && nx run-many -t typecheck,build,test,lint
Non-Nx Source (additional steps)
0. Import into apps/<name> (see SKILL.md: "Application vs Library Detection") 1. Generic fixes from SKILL.md (stale files cleanup, pnpm globs, rewritten scripts, target name prefixing, noEmit→composite, ESLint handling) 2. Fix noEmit in all tsconfigs (app, node, etc. — non-Nx projects often have multiple) 3. Add extends to solution-style tsconfigs so root settings apply 4. Fix resolve.alias / __dirname / baseUrl 5. Ensure types include vite/client and node 6. Install @nx/vite manually if it failed during import 7. Remove redundant npm scripts so @nx/vite/plugin infers them natively (see "Redundant npm Scripts" section) 8. Vue: Add outDir + **/*.vue.d.ts to ESLint ignores 9. Full verification
Multiple-Source Imports
See SKILL.md for generic multi-import (name collisions, dep refs). Vite-specific: fix tsconfig references paths for alternate directories (../../libs/ → ../../libs-beta/).
Non-Nx Source: React Router 7
1. Ensure source has at least one commit (see SKILL.md: "Source Repo Has No Commits") 2. nx import whole-repo into apps/<name> (see SKILL.md: "Application vs Library Detection") → auto-installs @nx/vite, @nx/react 3. Stale file cleanup: node_modules/, package-lock.json, .gitignore 4. Fix tsconfig.json: noEmit → composite + emitDeclarationOnly + outDir + tsBuildInfoFile 5. Add build and .react-router to dest root .gitignore 6. Keep all npm scripts — React Router 7 uses framework CLI (react-router build/dev), not plain vite (see "Redundant npm Scripts" above) 7. npm install && nx reset && nx sync --yes
Non-Nx Source: TanStack Start
1. Ensure source has at least one commit — create-tan-stack does NOT auto-commit (see SKILL.md) 2. nx import whole-repo into apps/<name> (see SKILL.md: "Application vs Library Detection") → auto-installs @nx/vite, @nx/vitest 3. Stale file cleanup: node_modules/, package-lock.json, .gitignore 4. Fix tsconfig.json: noEmit → composite + emitDeclarationOnly + outDir + tsBuildInfoFile 5. Keep allowImportingTsExtensions — compatible with emitDeclarationOnly: true 6. Add .vinxi, .tanstack, .nitro, .output to dest root .gitignore 7. Move hardcoded --port from dev script into vite.config.ts (server: { port: N }) 8. Remove redundant npm scripts — @nx/vite/plugin infers build, dev, preview, test (see "Redundant npm Scripts" above) 9. npm install && nx reset && nx sync --yes
Quick Reference: React vs Vue
| Aspect | React | Vue |
|---|---|---|
| Vite plugin | @vitejs/plugin-react | @vitejs/plugin-vue |
| Type checker | tsc | vue-tsc (auto-detected) |
| SFC support | N/A | vue-shims.d.ts needed |
| tsconfig jsx | "react-jsx" | "preserve" + "jsxImportSource": "vue" |
| ESLint parser | Standard TS | vue-eslint-parser + TS sub-parser |
| ESLint setup | Straightforward | Must install deps before @nx/eslint |
| Test utils | @testing-library/react | @vue/test-utils |
Quick Reference: Vite-Based React Frameworks
| Aspect | Vite (standalone) | React Router 7 | TanStack Start |
|---|---|---|---|
| Build config | vite.config.ts | vite.config.ts | vite.config.ts |
| Build output | dist/ | build/ | dist/ |
| SSR bundle | No | Yes (build/server/) | Yes (dist/server/) |
| tsconfig layout | app + node split | Single tsconfig | Single tsconfig |
| Auto-committed | Depends on tool | Usually yes | No — commit first |
nx import plugin | @nx/vite | @nx/vite, @nx/react | @nx/vite, @nx/vitest |
---
Iteration Log
Scenario 6: Multiple non-Nx React apps (CRA, Next.js, React Router 7, TanStack Start, Vite) → TS preset (PASS)
- Sources: 5 standalone non-Nx repos with different build tools
- Dest: CNW ts preset (Nx 22.5.1), npm workspaces,
packages/* - Import: whole-repo for each, sequential into
packages/<name> - Pre-import fixes:
1. Removed packages/.gitkeep and committed 2. git init && git add . && git commit in Vite app (no git at all) 3. git add . && git commit in TanStack app (git init'd but no commits)
- Import:
npm exec nx -- import <source> packages/<name> --source=. --ref=main --no-interactive - Next.js import auto-installed
@nx/eslint,@nx/next - React Router 7 import auto-installed
@nx/vite,@nx/react,@nx/docker(Dockerfile present) - TanStack import auto-installed
@nx/vitest - Post-import fixes:
1. Removed stale node_modules/, package-lock.json, .gitignore from each package 2. Removed Nx-rewritten scripts from board-games-nextjs/package.json (had "build": "nx next:build", etc.) 3. Updated root tsconfig.base.json: nodenext → bundler, added dom/dom.iterable to lib, added jsx: react-jsx 4. Added build to dest root .gitignore (CRA and React Router 7 output there) 5. Fixed noEmit → composite + emitDeclarationOnly in: board-games-vite/tsconfig.app.json, board-games-vite/tsconfig.node.json, board-games-react-router/tsconfig.json, board-games-tanstack/tsconfig.json 6. Fixed tsBuildInfoFile paths from ./node_modules/.tmp/... to ./dist/... 7. Installed root @types/react, @types/react-dom, @types/node
- All targets green:
buildfor all 5 projects;typecheckfor Vite/React Router/TanStack;next:buildfor Next.js
Related skills
How it compares
Use nx-import for repository migration into Nx rather than manual project.json and ESLint wiring from scratch.
FAQ
What does nx-import do?
Import, merge, or combine repositories into an Nx workspace using nx import. USE WHEN the user asks to adopt Nx across repos, move projects into a monorepo, or bring code/history from another repository.
When should I use nx-import?
When you need nx import help per SKILL.md.
Is nx-import safe to install?
Review the Security Audits panel on this page before installing in production.