Fix Turbopack's Wrong Workspace Root Warning
Trace the lockfile behind an unexpected workspace root, choose the right standalone or monorepo boundary, and separate a reported memory spike from a verified cause.
TL;DR#
If Turbopack says it inferred a workspace root that may be incorrect, read the selected directory, not just the list of lockfiles. A stray ancestor lockfile can select a directory above a standalone app. Set turbopack.root to the app's absolute directory, or to the common repository directory when sibling workspace packages are required. Restart and check the first route request. The warning alone does not prove a memory leak: the current-version test below reproduced the wrong root warning, but neither a Tailwind resolution loop nor memory exhaustion.
The warning that points above the application#
This warning was reproduced with an app under a deliberately empty parent directory:
⚠ Warning: Next.js inferred your workspace root, but it may not be correct.The next line identified the directory of /case/package-lock.json as the root. The app and its installed dependencies were actually under /case/Desktop/myapp. That difference is the diagnostic clue: the dependency lockfile selected as the workspace marker belongs to an ancestor, rather than the standalone application you intended to run.
The real incident behind this article is Next.js issue #92977. Its reporter used Next.js 16.2.4 on Windows and described an orphan lockfile in the user profile, repeated Tailwind resolution failures and a parent Node process reaching 43,516 MB. Those are reported observations, not measurements reproduced here. The issue was closed after the automated response said it lacked a valid reproduction link; that closure does not establish that a fix shipped.
The report also contains conflicting mitigation details: its opening says an explicit root worked, while a later section says deleting the orphan lockfile was still necessary. Treat it as a reason to investigate the path, not proof that every downstream CSS resolver always follows an explicit root. Confirm the result on the installed dependency versions.
Why it happens: lockfiles describe a filesystem boundary#
The Turbopack root documentation describes a root used for module resolution. The root must be absolute, and files beyond that boundary are excluded. Automatic detection uses recognised package-manager lockfiles; a folder you thought was unrelated can therefore influence the selected boundary.
An excessively broad root is relevant to performance because it expands the possible filesystem scope. The documentation warns against choosing a directory as broad as the user's home. That is a documented risk, but it does not establish the reporter's proposed chain of worker respawning, resolver retries and unbounded memory growth. No such causal chain was demonstrated by this article's test.
There is also an important current-version distinction. The tagged Next.js 16.4.4 root-discovery source gives workspace declarations precedence over ordinary lockfiles and applies Git repository, worktree and home-directory boundaries. A lockfile above a repository, or at the home-directory boundary, can be ignored rather than selected. This describes the inspected tag; it is not a claim that the original incident was fixed in that release.
Consequently, do not assume the closest lockfile always wins, or that the historical Windows example will behave identically today. Read the path printed by the installed Next.js version. A parent directory below the protected boundaries can still be selected, as the bounded test demonstrated.
Fix the inferred root without disturbing another project#
1. Inspect the application and its ancestors#
Stop the dev server with its terminal's interrupt command. From the application directory, check the installed version:
npm ls next --depth=0Compare the selected root from the warning with the directory containing the app's package manifest, Next.js configuration and dependency installation. On Windows, this PowerShell inspection lists relevant ancestor markers without changing them:
$rootCheck = (Get-Location).Path
$markerNames = @(
'package.json', 'package-lock.json', 'pnpm-lock.yaml',
'yarn.lock', 'bun.lock', 'bun.lockb',
'pnpm-workspace.yaml', 'lerna.json', '.git'
)
while ($rootCheck) {
foreach ($markerName in $markerNames) {
$markerPath = Join-Path $rootCheck $markerName
if (Test-Path -LiteralPath $markerPath) {
Get-Item -Force -LiteralPath $markerPath |
Select-Object FullName, PSIsContainer
}
}
$parentCheck = Split-Path -Parent $rootCheck
if ($parentCheck -eq $rootCheck) { break }
$rootCheck = $parentCheck
}A lockfile with no sibling manifest is suspicious, but inspect it before drawing a conclusion. A repository-level lockfile with a manifest declaring workspaces is a different situation: it may be the correct boundary for several applications. The marker list helps locate candidates; it is not a replacement implementation of Next.js root detection.
2. Set the intended absolute root in the existing config#
For a standalone application, merge the following into the existing next.config.mjs. Preserve other settings and any existing Turbopack rules; do not create a second competing configuration file.
import { fileURLToPath } from 'node:url'
const appRoot = fileURLToPath(new URL('.', import.meta.url))
const nextConfig = {
turbopack: {
root: appRoot,
},
}
export default nextConfigThis derives the directory from the configuration file itself. It avoids a hard-coded Windows username and does not depend on which directory an editor or task runner uses to launch the command. It also makes the choice reviewable in source control, so another developer can understand why automatic discovery was overridden.
For an existing CommonJS next.config.js, the equivalent standalone configuration is:
module.exports = {
turbopack: {
root: __dirname,
},
}Use the form matching the existing configuration module. The root setting belongs under the top-level Turbopack configuration documented above. A custom webpack callback does not express this filesystem boundary.
3. Remove an ancestor lockfile only if it is genuinely orphaned#
An accidental lockfile can be removed after its ownership is established. However, deleting every lockfile printed in the warning is the wrong diagnostic action: a real parent workspace may need its lockfile, and the application lockfile records its dependency graph.
Prefer the explicit root when the ancestor belongs to another legitimate project. If investigating the historical Tailwind symptom and the explicit root does not help, stop the server and inspect the ancestor file again. Move a confirmed accidental file to a recoverable location outside the ancestor chain, then restart and retest. Keep this separate from dependency upgrades or reinstallations so the result identifies which change mattered.
Verify the fix with a request, not just a ready message#
The bounded reproduction ran on 2 November 2026 in the official Node Linux image, with Node 24.22.2, Next.js 16.4.4, React 19.3.1 and Tailwind CSS 4.3.3. Dependencies were installed inside the container filesystem. The container had a 1536 MiB memory limit and a request timeout; it did not expose a host port or attempt to reproduce host RAM exhaustion.
The test app imported Tailwind through its PostCSS plugin and rendered a visible text marker. Its parent lockfile was outside a home directory and there was no Git repository boundary between that file and the app. Results were:
| Check | Automatic discovery | Explicit app root |
|---|---|---|
| Ancestor lockfile remains present | Yes | Yes |
| Incorrect-root warning | Present, selecting the parent directory | Absent |
| First route request | HTTP 200, marker present | HTTP 200, marker present |
| Tailwind resolution loop | Not observed | Not observed |
Only the configuration changed between those runs. This proves that an explicit root corrected the warning in that layout. It does not prove a memory reduction, a universal CSS fix, or a reproduction of the reported Windows failure.
A separate compatibility probe used the reported Next.js 16.2.4 version with React 19.2.4 and Tailwind CSS 4.2.1, under the same bounded Linux layout. It produced the same warning-before, warning-absent-after result, with HTTP 200 in both cases. This was not a replica of the reporter's Windows machine, and it did not reproduce the reported Tailwind resolution failure. Neither test supports treating a stray lockfile as a sufficient cause of severe RAM growth on every installation.
For your application, restart the same dev command and open the route that previously triggered the problem. Confirm that the inappropriate ancestor path is gone, CSS imports resolve and the page renders. Watch memory during the same bounded interaction, rather than leaving a visibly failing resolver running indefinitely. If memory still grows after the root is correct, retain that observation as a separate diagnostic result.
If the next message is specifically a V8 heap failure, continue with Ineffective mark-compacts near heap limit. That page distinguishes the main build process from a forked type checker and explains where a heap cap actually takes effect. Raising that cap does not correct a misplaced workspace root.
One email a month — the latest explained errors
What the site published that month — mostly Next.js, Supabase and Node errors, explained. You confirm by email; unsubscribe any time in one click.
Monorepos need a root containing the imported packages#
A standalone app can use its configuration directory as the root. A monorepo cannot blindly copy that choice if it imports sibling packages. For example, an app under apps/web and shared source under packages/ui need an appropriate common containing root. Narrowing the boundary to the app alone can exclude files the application legitimately requires.
For a configuration located at apps/web/next.config.mjs, a repository-root example is:
import { fileURLToPath } from 'node:url'
const repositoryRoot = fileURLToPath(new URL('../../', import.meta.url))
export default {
turbopack: {
root: repositoryRoot,
},
}The relative depth belongs to that specific layout. Confirm it points at the repository containing both directories before copying it. Keep the boundary as narrow as the application and its legitimate imports allow; selecting an entire user profile to make one linked package visible trades a clear layout problem for a much larger filesystem scope.
If the selected root is already correct and the only symptom is an unfinished compilation, use the broader Turbopack stuck on compiling troubleshooting page, which covers cache, import-graph and webpack fallback checks. It does not establish that a particular compilation hang came from a stray lockfile. If Next.js instead prints its explicit memory-restart message, the server running out of memory diagnostic addresses that symptom. Keep the first failing diagnostic attached to the evidence: the wrong root is fixed when the intended filesystem boundary is selected, while any remaining memory growth still needs its own explanation.
Frequently Asked Questions
Still stuck? Paste your error.
Paste the error message or stack trace — we check it against every fix and tool on the site.
Continue Reading
Fix Turbopack Build Errors from a Webpack Config
Find the plugin behind the unexpected webpack hook, choose a compiler deliberately, and verify that the behaviour you need still runs.
Can't Import SVG in Next.js: Fix for Turbopack and Webpack
Why <Logo /> fails with "Element type is invalid" or "Module parse failed", and the SVGR setups that build on Next.js 16 with both bundlers.
Fix 'Next.js 15 requires Node.js 18.18' Build Error
Next.js 15 drops support for older Node versions. Here is how to upgrade to Node.js 18.18.0 or later and fix build errors.


