Prisma client extensions in T3 app

T3 app uses this variable called globalThis and globalForPrisma. I don't understand the usage of it, but it nullifies the extended types. Can I just remove these and use new PrismaClient()? If not, what else can I do? - The file in question: src/server/db.ts - The page for client extensions: https://www.prisma.io/docs/concepts/components/prisma-client/client-extensions/result
Prisma
Prisma Client extensions: result component (Preview)
Extend the functionality of Prisma Client, result component
4 Replies
awexis
awexis12mo ago
https://www.prisma.io/docs/guides/other/troubleshooting-orm/help-articles/nextjs-prisma-client-dev-practices#solution This is the reason as to why. Though not sure if you can maybe make an object with your options. Then tack on the export const prisma line perhaps? Like
export const prisma =
globalForPrisma.prisma.$extends() ??
new PrismaClient({
log:
env.NODE_ENV === "development" ? ["query", "error", "warn"] : ["error"],
}).$extends();
export const prisma =
globalForPrisma.prisma.$extends() ??
new PrismaClient({
log:
env.NODE_ENV === "development" ? ["query", "error", "warn"] : ["error"],
}).$extends();
Maybe ?
Prisma
Best practice for instantiating PrismaClient with Next.js
Best practice for instantiating PrismaClient with Next.js
ahkhanjani
ahkhanjani12mo ago
Thanks a lot. Your solution is great but the problem remains because of:
const globalForPrisma = globalThis as unknown as {
prisma: PrismaClient | undefined;
};
const globalForPrisma = globalThis as unknown as {
prisma: PrismaClient | undefined;
};
No matter what it's force casting the generated types I am currently forcing my own client types I wrote manually everywhere I use them but that's just not scalable and safe
mrlowlevel
mrlowlevel12mo ago
We solved this like so:
export function getPrisma() {
return new BasePrismaClient({
// log: ['error'],
log:
env.NODE_ENV === 'development' ? ['query', 'error', 'warn'] : ['error'],
})
.$extends(brandExtension)
// ...
}

export type PrismaClient = ReturnType<typeof getPrisma>
export type TransactionClient = Parameters<
Parameters<PrismaClient['$transaction']>[0]
>[0]
export function getPrisma() {
return new BasePrismaClient({
// log: ['error'],
log:
env.NODE_ENV === 'development' ? ['query', 'error', 'warn'] : ['error'],
})
.$extends(brandExtension)
// ...
}

export type PrismaClient = ReturnType<typeof getPrisma>
export type TransactionClient = Parameters<
Parameters<PrismaClient['$transaction']>[0]
>[0]
And then use this PrismaClient type definition in the globals instead of the prisma-exported one
import { PrismaClient, getPrisma } from './prisma'

const globals = globalThis as unknown as {
__prisma: PrismaClient
}

export const prisma = globals.__prisma || getPrisma()
import { PrismaClient, getPrisma } from './prisma'

const globals = globalThis as unknown as {
__prisma: PrismaClient
}

export const prisma = globals.__prisma || getPrisma()
ahkhanjani
ahkhanjani11mo ago
This works! At least it seems to be at the moment I need to test it and inform you This is genius Thank you Why are we creating a function and returning instead of just creating an object?
const myPrisma = new BasePrismaClient({...});

type PrismaClient = typeof myPrisma;
const myPrisma = new BasePrismaClient({...});

type PrismaClient = typeof myPrisma;
What's the difference? This solution also sets the type of args of methods like findFirst and findMany to {} for some reason for the arguments of the methods you don't get autocompletion Is this a problem for you as well? I found the optimal solution to this:
const prismaX = new PrismaClient({
log: env.NODE_ENV === "development" ? ["query", "error", "warn"] : ["error"],
}).$extends({
result: {
...
},
});

type PrismaX = typeof prismaX;

const globalForPrisma = globalThis as unknown as {
prisma: PrismaX | undefined;
};

export const prisma = globalForPrisma.prisma ?? prismaX;

if (env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
const prismaX = new PrismaClient({
log: env.NODE_ENV === "development" ? ["query", "error", "warn"] : ["error"],
}).$extends({
result: {
...
},
});

type PrismaX = typeof prismaX;

const globalForPrisma = globalThis as unknown as {
prisma: PrismaX | undefined;
};

export const prisma = globalForPrisma.prisma ?? prismaX;

if (env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;