nextjs - 💡(How to fix) Fix Turbopack dev CSS @import resolves relative imports from workspace root in webpack SSR path [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#93426Fetched 2026-05-03 04:37:47
View on GitHub
Comments
1
Participants
2
Timeline
6
Reactions
0
Timeline (top)
labeled ×3closed ×1commented ×1locked ×1

Error Message

That mitigation makes the same workspace-root pnpm dev request return HTTP 200 for /login and eliminates the Can't resolve '../styles/globals.css' error. pnpm next dev --webpack continues to work.

Root Cause

where rootDir: ".." resolves to the workspace root, not the app directory. This is required because Turbopack rejects symlinked packages outside its filesystem root in our worktree/session setup.

Fix Action

Fix / Workaround

I do not yet have a public reducer. The reproducing repositories are private (siquora/stack-ui consuming a workspace-symlinked siquora/stack package), but the failure is deterministic there and the framework-side mitigation is small enough to identify the broken contract.

That mitigation makes the same workspace-root pnpm dev request return HTTP 200 for /login and eliminates the Can't resolve '../styles/globals.css' error. pnpm next dev --webpack continues to work.

Code Example

import { createMonorepoConfig } from "@siquora/stack/config";

const base = createMonorepoConfig({ rootDir: ".." });

const serverExternalPackages = (base.serverExternalPackages ?? []).filter(
  (pkg) => pkg !== "@siquora/stack",
);

export default {
  ...base,
  serverExternalPackages,
  transpilePackages: [...(base.transpilePackages ?? []), "@siquora/stack"],
};

---

outputFileTracingRoot: resolveRootDir(rootDir),
turbopack: { root: resolveRootDir(rootDir) },

---

@import "../styles/globals.css";
@import "./chat.css";
@import "./chat-widgets-index.css";

---

Can't resolve '../styles/globals.css' in '/Users/nmb/Projects/siquora'
  using description file: /Users/nmb/Projects/siquora/package.json (relative path: .)
    using description file: /Users/nmb/package.json (relative path: ./Projects/styles/globals.css)
      /Users/nmb/Projects/styles/globals.css doesn't exist

---

const path = module.require("node:path");

module.exports = function cssImportContextLoader(source, map, meta) {
  if (typeof this.resourcePath === "string" && this.resourcePath.length > 0) {
    this.context = path.dirname(this.resourcePath);
  }

  this.callback(null, source, map, meta);
};

---

Operating System:
  Platform: darwin
  Arch: arm64

Binaries:
  Node: v22.22.0
  pnpm: 10.33.2

Relevant Packages:
  next: 16.2.4
  react: 19.2.5
  react-dom: 19.2.5
  typescript: ^5
RAW_BUFFERClick to expand / collapse

Link to the code that reproduces this issue

I do not yet have a public reducer. The reproducing repositories are private (siquora/stack-ui consuming a workspace-symlinked siquora/stack package), but the failure is deterministic there and the framework-side mitigation is small enough to identify the broken contract.

I attempted a public pnpm-workspace reducer with the same high-level shape (direct-child Next app, symlinked workspace package imported from next.config.ts, the same package in transpilePackages, outputFileTracingRoot/turbopack.root pinned to the workspace root, a custom webpack callback, Tailwind/PostCSS, and src/app/globals.css importing ../styles/globals.css). That reduced case served /login successfully, so I am not publishing it as a misleading reproduction.

To Reproduce

Private repro shape:

  1. pnpm workspace root contains stack-ui/ and stack/ as sibling repos.
  2. stack-ui/node_modules/@siquora/stack is a workspace symlink to ../../../stack.
  3. stack-ui/next.config.ts imports framework config from the symlinked package:
import { createMonorepoConfig } from "@siquora/stack/config";

const base = createMonorepoConfig({ rootDir: ".." });

const serverExternalPackages = (base.serverExternalPackages ?? []).filter(
  (pkg) => pkg !== "@siquora/stack",
);

export default {
  ...base,
  serverExternalPackages,
  transpilePackages: [...(base.transpilePackages ?? []), "@siquora/stack"],
};
  1. The framework config sets both:
outputFileTracingRoot: resolveRootDir(rootDir),
turbopack: { root: resolveRootDir(rootDir) },

where rootDir: ".." resolves to the workspace root, not the app directory. This is required because Turbopack rejects symlinked packages outside its filesystem root in our worktree/session setup.

  1. stack-ui/src/app/globals.css contains:
@import "../styles/globals.css";
@import "./chat.css";
@import "./chat-widgets-index.css";
  1. Run pnpm dev from stack-ui/ and request /login.

Current vs. Expected behavior

Expected:

  • The relative CSS import in stack-ui/src/app/globals.css resolves from the importing file's directory.
  • GET /login returns 200 in dev mode.
  • pnpm next dev --webpack and next build behavior match dev Turbopack behavior.

Actual with Next.js 16.2.4:

  • The dev server reports Turbopack, but the failing resolver stack is webpack/enhanced-resolve from the SSR compilation path.
  • The relative CSS import is resolved from the workspace root instead of stack-ui/src/app/.
  • The request hangs/fails with:
Can't resolve '../styles/globals.css' in '/Users/nmb/Projects/siquora'
  using description file: /Users/nmb/Projects/siquora/package.json (relative path: .)
    using description file: /Users/nmb/package.json (relative path: ./Projects/styles/globals.css)
      /Users/nmb/Projects/styles/globals.css doesn't exist

The importer is stack-ui/src/app/globals.css line 10. Resolving ../styles/globals.css relative to that file is valid (stack-ui/src/styles/globals.css exists).

What fixes it locally

In the custom framework webpack callback, injecting a loader immediately before Next's CSS loader that sets the webpack loader context to path.dirname(this.resourcePath) fixes the issue:

const path = module.require("node:path");

module.exports = function cssImportContextLoader(source, map, meta) {
  if (typeof this.resourcePath === "string" && this.resourcePath.length > 0) {
    this.context = path.dirname(this.resourcePath);
  }

  this.callback(null, source, map, meta);
};

That mitigation makes the same workspace-root pnpm dev request return HTTP 200 for /login and eliminates the Can't resolve '../styles/globals.css' error. pnpm next dev --webpack continues to work.

This strongly suggests the SSR webpack CSS loader context is being initialized to a chunk/project/workspace context rather than the current CSS resource directory when the app uses Turbopack dev with a workspace-symlinked transpiled package and a custom webpack config.

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64

Binaries:
  Node: v22.22.0
  pnpm: 10.33.2

Relevant Packages:
  next: 16.2.4
  react: 19.2.5
  react-dom: 19.2.5
  typescript: ^5

Which area(s) are affected? (Select all that apply)

Turbopack, CSS, webpack/SSR dev compilation

Which stage(s) are affected? (Select all that apply)

next dev (local). Production next build is unaffected. next dev --webpack is unaffected.

Additional context

Related searches before filing:

  • #85315 covers Turbopack + transpilePackages in monorepos, but its reported failure is TypeScript/package export resolution, not CSS @import context.
  • #90307 was a CSS @import context report but was closed for lack of a public repro and appears focused on turbopack.root === dir; in this case turbopack.root intentionally points at the workspace root to keep symlinked packages inside Turbopack's filesystem boundary.

I can provide more trace/detail from the private repro if useful, and I will update this issue if I find a public reducer that actually fails.

extent analysis

TL;DR

The issue can be fixed by injecting a custom loader in the webpack callback to set the loader context to the directory of the current CSS resource.

Guidance

  • Identify the custom webpack callback in the framework configuration and inject a loader to set the context.
  • Use the path.dirname(this.resourcePath) to determine the directory of the current CSS resource.
  • Apply this fix only in the development environment, as production builds are unaffected.
  • Verify that the fix resolves the CSS import issue and allows the development server to return a 200 status code for the /login request.

Example

const path = module.require("node:path");

module.exports = function cssImportContextLoader(source, map, meta) {
  if (typeof this.resourcePath === "string" && this.resourcePath.length > 0) {
    this.context = path.dirname(this.resourcePath);
  }

  this.callback(null, source, map, meta);
};

Notes

This fix is specific to the development environment with Turbopack and a custom webpack configuration. The production build is unaffected, and this fix may not be necessary in other environments.

Recommendation

Apply the custom loader workaround to fix the CSS import issue in the development environment. This fix is necessary because the SSR webpack CSS loader context is being initialized to a chunk/project/workspace context rather than the current CSS resource directory.

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

nextjs - 💡(How to fix) Fix Turbopack dev CSS @import resolves relative imports from workspace root in webpack SSR path [1 comments, 2 participants]