nextjs - 💡(How to fix) Fix Setting turbopack.root to project directory breaks CSS @import resolution [1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
vercel/next.js#90307Fetched 2026-04-08 00:20:26
View on GitHub
Comments
1
Participants
2
Timeline
4
Reactions
0
Timeline (top)
closed ×1commented ×1labeled ×1locked ×1

Error Message

Error: Can't resolve 'tailwindcss' in '/Users/user/Projects'

Root Cause

Confirmed root cause (JS side)

Fix Action

Fix / Workaround

  • Setting turbopack.root to the project directory is a reasonable use case (e.g. to silence the multiple-lockfile warning).
  • Bug only manifests with Turbopack. Webpack (production build) is unaffected.
  • Workaround: Remove turbopack.root and ignore the warning.

Code Example

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin 24.6.0

Binaries:
  Node: 22.x
  pnpm: 9.x

Relevant Packages:
  next: 16.1.6
  react: 19.x
  @tailwindcss/postcss: 4.2.0
  tailwindcss: 4.2.0

---

export default { plugins: { "@tailwindcss/postcss": {} } };

---

@import 'tailwindcss';

---

const nextConfig = {
     turbopack: {
       root: __dirname, // e.g. /Users/user/Projects/myapp
     },
   };
   export default nextConfig;

---

Error: Can't resolve 'tailwindcss' in '/Users/user/Projects'

---

const rootPath = config.turbopack?.root || dir;
const projectPath = path.relative(rootPath, dir) || '.';

---

// Current (buggy)
const projectPath = path.relative(rootPath, dir) || '.';

// Suggested
const projectPath = path.relative(rootPath, dir); // "" means same dir
RAW_BUFFERClick to expand / collapse

Verify canary release

  • I verified that the issue exists in the latest Next.js canary release

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin 24.6.0

Binaries:
  Node: 22.x
  pnpm: 9.x

Relevant Packages:
  next: 16.1.6
  react: 19.x
  @tailwindcss/postcss: 4.2.0
  tailwindcss: 4.2.0

Which area(s) are affected?

Turbopack, CSS

To Reproduce

  1. Create a Next.js 16 project with Tailwind CSS v4 using @tailwindcss/postcss and pnpm.

  2. postcss.config.mjs:

    export default { plugins: { "@tailwindcss/postcss": {} } };
  3. In a CSS file (e.g. src/styles/globals.css):

    @import 'tailwindcss';
  4. Set turbopack.root in next.config.ts:

    const nextConfig = {
      turbopack: {
        root: __dirname, // e.g. /Users/user/Projects/myapp
      },
    };
    export default nextConfig;
  5. Run pnpm dev.

  6. Error:

    Error: Can't resolve 'tailwindcss' in '/Users/user/Projects'

    The project lives at /Users/user/Projects/myapp, but resolution starts from /Users/user/Projects (the parent).

Expected Behavior

Setting turbopack.root to the project directory should be a no-op. CSS @import should resolve from the project root, finding node_modules/tailwindcss.

Current Behavior

Resolution starts from the parent directory and never reaches myapp/node_modules/.

Confirmed root cause (JS side)

In packages/next/src/server/dev/hot-reloader-turbopack.ts:

const rootPath = config.turbopack?.root || dir;
const projectPath = path.relative(rootPath, dir) || '.';

When root === dir, path.relative() returns "", and || '.' kicks in → projectPath = ".".

This "." is passed to the Turbopack Rust layer via NapiProjectOptions.

Theoretical analysis (Rust side — not yet confirmed by debugging)

Based on reading the source code, the likely downstream effect is:

  • get_relative_path_to(".", "src/styles/globals.css") may treat "." as a literal path segment rather than "current directory", producing "../src/styles/globals.css" instead of "./src/styles/globals.css".
  • @tailwindcss/postcss would then resolve this with path.resolve(process.cwd(), "../src/styles/globals.css"), which goes to the parent directory.

Note: This Rust-side analysis is theoretical. normalize_path(".") in turbo-unix-path may correctly convert "." to "" — we have not confirmed whether the "." actually leaks through to get_relative_path_to. The exact mechanism in the Rust layer needs to be verified with runtime debugging.

What is confirmed

  • The JS side produces projectPath = "." when root === dir
  • The CSS resolution context ends up as dirname(root) (the parent directory)
  • Without turbopack.root, CSS resolution works correctly

Suggested fix

The || '.' fallback on the JS side seems unnecessary and potentially harmful:

// Current (buggy)
const projectPath = path.relative(rootPath, dir) || '.';

// Suggested
const projectPath = path.relative(rootPath, dir); // "" means same dir

Additional Context

  • Setting turbopack.root to the project directory is a reasonable use case (e.g. to silence the multiple-lockfile warning).
  • Bug only manifests with Turbopack. Webpack (production build) is unaffected.
  • Workaround: Remove turbopack.root and ignore the warning.

Related issues

  • #72174 — Tailwind not working with Turbopack + pnpm
  • #72761 — @import on CSS not working with Turbopack

extent analysis

Fix Summary

The bug is caused by the || '.' fallback in hot-reloader-turbopack.ts. When turbopack.root equals the project directory, path.relative(root, dir) returns an empty string (""). The fallback turns this into ".", which Turbopack’s Rust side treats as a literal path segment and makes CSS imports resolve from the parent directory.
Fix: Remove the fallback so that an empty string is passed through unchanged.


Step‑by‑Step Fix Plan

1. Apply the source change in Next.js

Edit packages/next/src/server/dev/hot-reloader-turbopack.ts.

@@
- const rootPath = config.turbopack?.root || dir;
- const projectPath = path.relative(rootPath, dir) || '.';
+ const rootPath = config.turbopack?.root || dir;
+ // When root === dir `path.relative` returns "" (same folder).  Do **not**
+ // replace it with "." – an empty string is the correct “no‑sub‑path” value.
+ const projectPath = path.relative(rootPath, dir);

2. Re‑build the Next.js package (if you’re using a local copy)

# From the repo root
pnpm install

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING