Skip to content

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.

// 💢 BAD: Static import pulls database into client bundle
import { db } from '@/api/database';
export async function createUser(input) {
return db.user.create({ data: input });
}
'use server';
// GOOD: Type-only import is stripped at build time
import 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 } });
}
'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 });
}
'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);
}
  1. Server actions: Use 'use server' directive
  2. Database imports: Always dynamic
  3. Type imports: Use import type
  4. Procedure calls: Use executeProcedureDirectly bridge