4.0 KiB
Postmortem: Client-Side Import of Server Package
Issue Reference
Summary
Users are incorrectly importing the server-side better-auth package
directly in their client-side code, causing build and runtime errors.
This is a common user mistake that keeps resurfacing.
Root Cause
The Problematic Import Chain
Users create this incorrect dependency chain in their client code:
loginPage (React/Vue/Solid component)
↓
auth-client.ts
↓
import { ... } from "better-auth" ← WRONG!
This is 100% a user error. The correct import should be:
// WRONG - Server package in client code
import { ... } from "better-auth"
// CORRECT - Client package for client code
import { createAuthClient } from "better-auth/client"
Why This Happens
- Confusing package naming - Users assume
better-authis the main entry point for everything - Auto-import suggestions - IDEs often suggest the wrong import
- Copy-paste from examples - Users copy server examples into client code
- Lack of clear error messages - Build errors do not clearly explain the import boundary violation
The Real Problem
When users import better-auth in client code:
- Node.js modules get bundled - Server-only dependencies like
node:sqliteend up in client bundles - Build failures - Bundlers cannot resolve Node.js built-ins
- Runtime errors - Even if builds succeed, code fails in browser
- Increased bundle size - Unnecessary server code shipped to client
Why PR #4360 Was Incorrectly Blamed
PR #4360 added a typeof window === "undefined" check to prevent
node:sqlite errors.
This was a workaround, not the cause.
The real issue is users importing server packages in client code.
Solution
For Users
// In any client-side file (React, Vue, Solid, etc.)
// NEVER do this:
import { anything } from "better-auth"
// ALWAYS do this:
import { createAuthClient } from "better-auth/client"
import type { Session, User } from "better-auth/types"
For the Library
- Better error messages - Detect client environment and throw clear errors when server package is imported
- Build-time detection - Add package.json exports that prevent incorrect imports
- Documentation - Make the distinction crystal clear
Changes in PR #7532
While fixing test infrastructure, the real issue was revealed:
- Test cleanup - Fixed window stubbing (secondary issue)
- Import boundaries - The tests exposed that server code was being imported in client contexts
Lesson Learned
- Users will make this mistake - The naming is confusing
- Workarounds hide root causes - Adding
windowchecks does not fix users importing the wrong package - Clear boundaries needed - Server and client packages must be clearly separated
- This is not a regression - It is an ongoing user education issue
Prevention
Immediate Actions
-
Add runtime detection:
// In better-auth/index.ts if (typeof window !== "undefined") { throw new Error( "You are importing 'better-auth' in client code. " + "Use 'better-auth/client' instead." ); } -
Update documentation - Add prominent warnings about imports
-
Fix auto-imports - Configure package.json to guide IDEs
Long-term Solutions
-
Build-time validation - ESLint plugin to catch wrong imports
-
Better examples - Clearly separate server and client code
User Action Required
If you are seeing build errors with node:* modules:
- Check your imports - You are importing
better-authin client code - Fix the import - Change to
better-auth/client - Never import server packages in client code
This is not a bug in Better Auth - it is incorrect usage.