Turbopack serverExternalPackages Not Found with pnpm? Fix It

Turbopack serverExternalPackages Not Found with pnpm Child Dependencies? Here's the Fix
If you've been working with Next.js 15+ and Turbopack, you might have encountered a frustrating error when running pnpm dev --turbo:
Package @libsql/client (serverExternalPackages or default list) can't be external
The request @libsql/client matches serverExternalPackages (or the default list),
but it can't be external: The request could not be resolved by Node.js from the
project directory.
This error is particularly insidious because it only occurs with pnpm and specifically affects child dependencies—packages that are dependencies of your direct dependencies. Webpack handles this gracefully, npm with --legacy-peer-deps works fine, and even Yarn has no issues. So what's happening with Turbopack serverExternalPackages pnpm setups?
Let's dive deep into this niche but impactful issue and explore exactly how to fix it.
The Problem: Turbopack Failing to Locate serverExternalPackages in pnpm Setups
The core issue, documented in GitHub issue #68805, is that Turbopack cannot locate packages listed in serverExternalPackages when those packages are transitive dependencies installed via pnpm.
Consider this scenario: You're using a library like payload (a headless CMS) which internally depends on @libsql/client. You haven't directly installed @libsql/client in your project—it comes along as a child dependency. When Turbopack tries to externalize this package (either via your config or the default list), it fails to resolve it from the project root.
The error manifests during development with Turbopack enabled:
pnpm dev --turboYour terminal floods with errors for packages like @libsql/client, @prisma/client, sharp, and other popular packages that Next.js automatically externalizes. These packages are on Next.js's default external packages list, but Turbopack can't find them in pnpm's node_modules structure.
Understanding the Stack: Turbopack, serverExternalPackages, and pnpm's Unique Hoisting
To understand why this happens, we need to examine three key technologies:
Turbopack's Module Resolution
Turbopack, Next.js's Rust-based bundler, handles server-side code differently than Webpack. When a package is marked as external (via serverExternalPackages), Turbopack expects to resolve it using Node.js's native require() from the project root directory. This is intentional—external packages need to be resolvable at runtime from the output files.
The serverExternalPackages Configuration
Introduced as stable in Next.js 15 (previously experimental.serverComponentsExternalPackages), this configuration tells Next.js to opt specific packages out of bundling:
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
serverExternalPackages: ['@acme/ui', 'some-native-module'],
}
module.exports = nextConfigPackages using Node.js-specific features (native bindings, file system operations, etc.) often need this configuration. Next.js maintains a default list of such packages that are automatically externalized.
pnpm's Strict Dependency Isolation
Here's where the Turbopack serverExternalPackages pnpm conflict emerges. pnpm uses a unique node_modules structure:
- Flat hoisting is disabled by default: Dependencies are nested under
.pnpm/with symlinks - Strict dependency isolation: A package can only access its declared dependencies
- Content-addressable storage: Packages are stored in a global store and linked
This means that when payload depends on @libsql/client, that dependency lives within:
node_modules/.pnpm/[email protected]/node_modules/@libsql/client
Not in:
node_modules/@libsql/client ← Where Turbopack looks
Why This Happens: Deep Dive into Dependency Resolution Differences and Module Graph
The fundamental issue is a mismatch between how Turbopack resolves external packages and how pnpm structures dependencies.
Turbopack's Resolution Strategy
When Turbopack encounters a package marked for externalization, it:
- Removes the package from the bundle
- Generates a runtime
require('package-name')call - Validates that Node.js can resolve this package from the project directory
Step 3 is where things break. Turbopack performs this validation at build time to ensure the output will work at runtime. It uses Node.js's resolution algorithm starting from the project root.
pnpm's Module Graph
pnpm's symlink-based structure creates a different module graph:
your-project/
├── node_modules/
│ ├── .pnpm/ # Content-addressable store
│ │ ├── [email protected]/
│ │ │ └── node_modules/
│ │ │ ├── payload/ # The actual package
│ │ │ └── @libsql/client/ # Dependency symlink
│ │ └── @[email protected]/
│ │ └── node_modules/
│ │ └── @libsql/client/ # Actual package files
│ └── payload -> .pnpm/[email protected]/node_modules/payload
└── package.json # Only lists `payload`
When Node.js resolves @libsql/client from the project root, it can't find it because it's not hoisted there.
The npm/Yarn Difference
npm and Yarn use flat hoisting by default. With npm install --legacy-peer-deps or Yarn:
your-project/
├── node_modules/
│ ├── payload/
│ ├── @libsql/
│ │ └── client/ # Hoisted to root!
│ └── ...
└── package.json
This is why the same project works with npm/Yarn but fails with pnpm—the packages exist where Turbopack expects them.
Reproducing the Issue: Minimal Example for pnpm Child Dependencies
Let's create a minimal reproduction to understand the issue clearly:
Step 1: Initialize a Next.js Project with pnpm
pnpm create next-app@latest turbopack-pnpm-test
cd turbopack-pnpm-testStep 2: Add a Library with Transitive Dependencies
Install a package that depends on something on Next.js's default external list:
pnpm add payload # or any package depending on @libsql/client, @prisma/client, etc.Step 3: Attempt to Run Turbopack
pnpm dev --turboYou'll see errors like:
Package @libsql/client (serverExternalPackages or default list) can't be external
The request @libsql/client matches serverExternalPackages (or the default list),
but it can't be external: The request could not be resolved by Node.js from the
project directory. Packages that should be external need to be installed in the
project directory, so they can be resolved from the output files.
Try to install the package into the project directory.
Step 4: Verify It Works with npm
rm -rf node_modules pnpm-lock.yaml
npm install --legacy-peer-deps
npm run dev -- --turbo # Works!This confirms it's specifically a Turbopack serverExternalPackages pnpm interaction issue, not a general Turbopack bug.
The Fix: Correctly Configuring serverExternalPackages and pnpm Workspaces
There are several approaches to fix this issue, depending on your project needs:
Solution 1: Explicitly Install Transitive Dependencies
The most straightforward fix is to add the problematic packages as direct dependencies:
pnpm add @libsql/client @prisma/client sharpThis hoists them to your project's node_modules, making them resolvable from the root:
// package.json
{
"dependencies": {
"payload": "^2.0.0",
"@libsql/client": "^0.5.0", // Now directly installed
"@prisma/client": "^5.0.0" // Now directly installed
}
}Pros: Simple, immediate fix
Cons: Duplicates dependency declarations, version management overhead
Solution 2: Configure pnpm Public Hoisting
Modify .npmrc to enable public hoisting for specific packages:
# .npmrc
public-hoist-pattern[]=@libsql/client
public-hoist-pattern[]=@prisma/client
public-hoist-pattern[]=sharpOr enable broader hoisting (less strict isolation):
# .npmrc
shamefully-hoist=truePros: No need to modify package.json
Cons: shamefully-hoist weakens pnpm's isolation benefits; pattern-based hoisting requires maintenance
Solution 3: Use pnpm Workspaces with Explicit Dependencies
For monorepos, ensure the affected packages are listed at the workspace root:
# pnpm-workspace.yaml
packages:
- 'apps/*'
- 'packages/*'// Root package.json
{
"dependencies": {
"@libsql/client": "^0.5.0"
}
}Solution 4: Exclude Packages from serverExternalPackages
If you don't need the package to be external (it doesn't use native Node.js features), explicitly bundle it by setting an empty array or managing the list manually:
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
// Override the default list if needed
serverExternalPackages: [], // Bundle everything
}
module.exports = nextConfigWarning: This may cause issues if the package genuinely requires native Node.js features.
Best Practices: Managing External Dependencies in Turbopack with pnpm
Based on the analysis and solutions above, here are recommended practices for Turbopack serverExternalPackages pnpm configurations:
1. Audit Your Dependency Tree
Before configuring anything, understand which packages are being externalized:
pnpm why @libsql/client
pnpm why @prisma/clientThis shows you the dependency chain and helps identify what needs hoisting.
2. Use Selective Hoisting Over shamefully-hoist
Create a targeted .npmrc configuration:
# .npmrc
# Only hoist packages that need to be external
public-hoist-pattern[]=@libsql/client
public-hoist-pattern[]=@prisma/client
public-hoist-pattern[]=sharp
public-hoist-pattern[]=@node-rs/*
public-hoist-pattern[]=bcrypt
public-hoist-pattern[]=argon2This preserves pnpm's strict isolation while fixing the specific resolution issue.
3. Document External Dependencies
Maintain a clear record of why certain packages are hoisted or directly installed:
// package.json
{
"pnpm": {
"overrides": {
"// @libsql/client": "Hoisted for Turbopack compatibility"
}
},
"dependencies": {
"@libsql/client": "^0.5.0"
}
}4. Monitor Next.js Updates
The Turbopack team is actively improving pnpm compatibility. Track GitHub issue #68805 for updates. This behavior first appeared in Next.js 15.0.0-canary.84 and may be addressed in future versions.
5. Consider Turbopack Stability
As of late 2024, Turbopack is marked stable for development but may still have edge cases. For production builds, Webpack remains the default. Evaluate whether Turbopack's speed benefits outweigh configuration complexity for your specific Turbopack serverExternalPackages pnpm setup.
Related Considerations: Monorepos and Alternative Package Managers
Monorepo Implications
In monorepo setups (Turborepo, Nx, etc.), this issue compounds:
- Each workspace may have different transitive dependencies
- Hoisting patterns must be coordinated across the entire workspace
- Root-level dependencies affect all packages
Recommendation: Centralize externalized dependencies in the root package.json and use pnpm's workspace protocol:
// Root package.json
{
"dependencies": {
"@libsql/client": "workspace:*"
}
}Alternative Package Managers
If you're evaluating package managers for a Next.js + Turbopack project:
| Package Manager | Turbopack Compatibility | Trade-offs |
|---|---|---|
| npm | ✅ Full | Slower installs, disk space |
| Yarn Classic | ✅ Full | Legacy, limited features |
| Yarn Berry | ⚠️ Varies | PnP mode has its own issues |
| pnpm | ⚠️ Requires config | Strict isolation conflicts |
| Bun | ✅ Full | Node.js compatibility gaps |
For maximum compatibility, npm with lockfile caching or Yarn Classic remain the safest choices with Turbopack.
Key Takeaways
- The root cause: Turbopack validates that
serverExternalPackagescan be resolved from the project root, but pnpm's strict isolation prevents transitive dependencies from being hoisted there. - Primary fix: Explicitly install transitive dependencies that Turbopack externalizes (
pnpm add @libsql/client). - Alternative fix: Configure pnpm's
.npmrcwith selectivepublic-hoist-patternentries for affected packages. - Track the issue: GitHub issue #68805 documents this behavior—star it for updates.
- Evaluate your stack: Consider whether pnpm's strict isolation benefits outweigh the configuration overhead for Turbopack projects.
Next Steps
- Audit your project: Run
pnpm why <package>for any packages in Turbopack's error messages - Apply the fix: Choose between direct installation or
.npmrchoisting based on your project structure - Regenerate lockfile: After changes, run
pnpm installto updatepnpm-lock.yaml - Test thoroughly: Run
pnpm dev --turboand verify all routes compile successfully - Monitor updates: Watch the Next.js releases for potential fixes to this behavior
By understanding how Turbopack serverExternalPackages pnpm interactions differ from Webpack's more forgiving resolution, you can configure your Next.js project for reliable development server performance without abandoning pnpm's efficiency benefits.
Tags
Faucetspro
Content creator and developer at UICraft Marketplace, sharing insights and tutorials on modern web development.
Build Your Next Project Faster
Save hours of development time with our premium Next.js templates. Built with Next.js 16, React 19, and Tailwind CSS 4.
Subscribe to our newsletter
Get the latest articles, tutorials, and product updates delivered to your inbox.
Related Articles

Why Next.js App Router Singletons Are Inconsistent (And How to Fix It)
The Next.js App Router introduced in version 14.2.3+ has a critical singleton instantiation issue affecting database connections, syntax highlighters, and module-level state. This guide explains why singletons behave inconsistently during builds and provides battle-tested solutions.

Fix: Why 'use cache' Is Ignored in Next.js Dynamic Routes (and Correct Usage)
Confused why your 'use cache' directive isn't working in Next.js dynamic routes? This guide explains the key difference between development and production behavior, reveals the generateStaticParams requirement, and provides proven patterns for implementing caching correctly.

Why Next.js RSC Performance Suffers with CDNs in Highload Projects (And How to Fix It)
React Server Components (RSC) promise excellent performance, but pairing them with CDNs in highload scenarios introduces unexpected challenges. Learn why RSC payloads create unique caching friction points and how to optimize your architecture for global scale.