Skip to content

RSC Module Separation

When using RSC, maintain strict module boundaries to prevent Node.js code from leaking into client bundles.

// 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