The client
db is a Drizzle client over node-postgres. It is server-only:
the package resolves a different module depending on the bundler's export condition.
Server implementation
The real client — the default (and SSR) condition. DATABASE_URL comes from the environment,
and the full schema is attached so relational queries are typed:
import { drizzle } from "drizzle-orm/node-postgres";
import * as schema from "./schema";
export const db = drizzle(process.env.DATABASE_URL!, { schema });
export * from "./schema";Browser stub
Any client bundle resolves the browser condition to this stub. Every property access throws, so
pg and its Node-only dependencies can never end up in the client bundle:
/**
* Browser-side stub for @tikab-interactive/fusion-db. The real Drizzle client requires the pg
* Node driver which pulls in Buffer/events APIs that don't exist in browsers.
* Any client-side import resolves to this stub, which throws if used.
* Server-only code (createServerFn handlers, route loaders) hit the real
* implementation because Vite picks the "node" export condition in SSR.
*/
const handler: ProxyHandler<object> = {
get() {
throw new Error(
"@tikab-interactive/fusion-db is server-only. Access it from a createServerFn handler.",
);
},
};
export const db = new Proxy({}, handler) as never;
export * from "./schema";Using it
Call it from a server function or route loader — never from a component. Drizzle operators like
eq come from drizzle-orm; the tables come from fusion-db:
import { eq } from "drizzle-orm";
import { db, user } from "@tikab-interactive/fusion-db";
export async function getUser(id: string) {
const [row] = await db.select().from(user).where(eq(user.id, id));
return row;
}If this runs in a browser bundle by mistake, the stub throws immediately with a clear
"server-only" error rather than failing deep inside pg.