RSC Module Separation
React Server Components make it easy to accidentally pull Node.js dependencies into the client bundle. This page covers the module boundary patterns that keep your builds clean and your bundles lean.
Why Module Boundaries Matter
Section titled “Why Module Boundaries Matter”// 💢 BAD: Static import pulls database into client bundleimport { db } from '@/api/database';
export async function createUser(input) { return db.user.create({ data: input });}The Solution
Section titled “The Solution”1. Type-Only Imports
Section titled “1. Type-Only Imports”'use server';
// GOOD: Type-only import is stripped at build timeimport type { User } from '@/api/schemas/user';
export async function getUser(id: string): Promise<User> { const { db } = await import('@/api/database'); return db.user.findUniqueOrThrow({ where: { id } });}2. Dynamic Imports
Section titled “2. Dynamic Imports”'use server';
export async function createUser(input: CreateUserInput) { // GOOD: Dynamic import at runtime const { db } = await import('@/api/database'); return db.user.create({ data: input });}3. Procedure Bridge
Section titled “3. Procedure Bridge”'use server';
export async function createUser(input: CreateUserInput) { const { executeProcedureDirectly } = await import('@veloxts/web/server'); const { userProcedures } = await import('@/api/procedures/users');
return executeProcedureDirectly(userProcedures.procedures.createUser, input);}Best Practices
Section titled “Best Practices”- Server actions: Use
'use server'directive - Database imports: Always dynamic
- Type imports: Use
import type - Procedure calls: Use
executeProcedureDirectlybridge
Related Content
Section titled “Related Content”- Server Actions - Action patterns
- tRPC Bridge - Procedure calls