prisma: `Error: PrismaClient is unable to be run in the browser.`

Bug description

use prisma in next.js 13.4.4 middleware. give this error Error: PrismaClient is unable to be run in the browser. 微信截图_20230529214419

How to reproduce

create a next.js (13.4.4) project init prisma create a middleware.ts file, import prisma see error

Expected behavior

No response

Prisma information

// Add your schema.prisma
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "sqlite"
  url      = env("DATABASE_URL")
}

// 用户
model User {
  id       Int       @id @default(autoincrement())
  username String    @unique
  password String
  disable  Boolean?
  realname String?
  avtar    String?
  gender   String?
  email    String?
  phone    String?
  birthday DateTime?
}
// prisma.ts
import { PrismaClient } from "@prisma/client";

console.log("what fuck");

const globalForPrisma = global as unknown as {
  prisma: PrismaClient | undefined;
};

export const prisma =
  globalForPrisma.prisma ?? new PrismaClient({ log: ["query"] });

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

// middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest, NextFetchEvent } from "next/server";
import { prisma } from "./prisma/prisma";

export function middleware(request: NextRequest, event: NextFetchEvent) {
  const aUser = prisma.user.findFirst();
  console.log(aUser);

  return NextResponse.next();
}

export const config = {
  matcher: ["/admin/:path*"],
};

Environment & setup

  • OS: Window11
  • Database: SQlite
  • Node.js version:v18.16.0

Prisma Version

prisma                  : 4.14.1
@prisma/client          : 4.14.1
Current platform        : windows
Query Engine (Node-API) : libquery-engine d9a4c5988f480fa576d43970d5a23641aa77bc9c (at node_modules\@prisma\engines\query_engine-windows.dll.node)
Migration Engine        : migration-engine-cli d9a4c5988f480fa576d43970d5a23641aa77bc9c (at node_modules\@prisma\engines\migration-engine-windows.exe)
Format Wasm             : @prisma/prisma-fmt-wasm 4.14.0-67.d9a4c5988f480fa576d43970d5a23641aa77bc9c
Default Engines Hash    : d9a4c5988f480fa576d43970d5a23641aa77bc9c
Studio                  : 0.484.0

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Comments: 31 (6 by maintainers)

Most upvoted comments

Looks like https://github.com/vercel/next.js/discussions/40416#discussioncomment-3613207, where icyJoseph explains you can’t use prisma in the middleware. I solved it myself by creating an API call that does the database interaction, and returns the data as a JSON response, and use fetch() to that API call in the middleware

after a due while, there has not a new idea, it seem’s will be a long road wait… i change my mind, use fetch to do auth instead of directlly use prisma function in middleware, change the prisma part code from middleware to api, i have create a template project for it : https://github.com/hohogpb/next-prisma-auth-starter online demo : https://next-prisma-auth-starter.vercel.app/

@janpio I ended up resolving this. The issue was that the server component was an edge server component. I updated my comment to include the edge runtime declaration, which caused the prisma error.

For people running into this error with next.js Prisma does alert you that it can’t run in edge. I specifically did not get this error because my next cache was out of date. A seriously frustrating issue IMO. I had to rm -rf .next and rm -rf node_modules, then npm i and npm run dev to get the updated error, which alerted me to look for a component inheriting the code block referencing prisma that was running on edge.

Similar issue here. Ultimately I chose to go with an api route and posting the data to it however it would be great to just use server components.

simple example below:

middleware.ts

import { authMiddleware } from "@clerk/nextjs";
import { createUser } from "./lib/database/createUser";

export default authMiddleware({
  publicRoutes: ["/", "/api/auth/public(.*)"],
  ],
  async afterAuth(auth, req, evt) {
    if (!auth.userId) {
      return;
    }
    try {
      if (auth.user) {
        const userData: UserData = {
          clerkId: auth.userId,
          email: auth.user.emailAddresses?.[0].emailAddress,
          name: `${auth.user.firstName} ${auth.user.lastName}`,
          profileImageUrl: auth.user.profileImageUrl,
        };
        const res = await createUser(userData);
        const responseData = await res.json();
        if (!responseData.ok) {
          console.error("Error creating user", responseData.error);
          throw new Error(`User creation failed: ${responseData.error}`);
        }
      }
    } catch (error) {
      console.error("Error in afterAuth:", error);
    }
  },
});

export const config = {
  matcher: ["/((?!.*\\..*|_next).*)", "/(api|trpc)(.*)"],
};

lib/database/createUser.ts

"use server";
import { NextResponse } from "next/server";
import { UserData } from "@/typings";
import { prisma } from "./prisma-client";
import { User } from "@prisma/client";

type UserCreationResponse =
  | { ok: true; data: User }
  | { ok: false; error: string };

export async function createUser(
  userData: UserData,
): Promise<NextResponse<UserCreationResponse>> {
  try {
    const dbUser = await prisma.user.create({
      data: {
        externalId: userData.clerkId,
        email: userData.email,
        name: userData.name,
        profileImageUrl: userData.profileImageUrl,
      },
    });

    if (!dbUser) {
      return NextResponse.json({
        ok: false,
        error: "Error creating user",
      });
    }

    return NextResponse.json({
      ok: true,
      data: dbUser,
    });
  } catch (error) {
    throw error;
  }
}

//prisma-client.ts

"use server";
import { PrismaClient } from "@prisma/client";

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

export const prisma = globalForPrisma.prisma ?? new PrismaClient();

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

Run into this few days back, Problem is calling Prisma on the client; use native fetch or even better use axios to call api endpoint, Access prisma in the api routes. Happy coding. 😃

Looks like vercel/next.js#40416 (comment), where icyJoseph explains you can’t use prisma in the middleware. I solved it myself by creating an API call that does the database interaction, and returns the data as a JSON response, and use fetch() to that API call in the middleware

Did you make an API, still internally in NextJS as a Monorepo or did you have to make an external API?

I created a file in src/app/api/user/route.ts which contains something like this:

import { notFound } from 'next/navigation'
import { NextRequest, NextResponse } from 'next/server'
import { getToken } from 'next-auth/jwt'

import { db } from '@web/registry'

export const GET = async (request: NextRequest) => {
  const token = await getToken({ req: request })
  if (!token || !token.sub) {
    return new NextResponse('Unauthorized', { status: 403 })
  }

  const user = await db().user.findUnique({ where: { id: BigInt(token.sub) } })
  if (!user) {
    return notFound()
  }

  return NextResponse.json({
    user: {
      id: user.id.toString(),
      name: user.name,
      email: user.email,
      image: user.image,
    },
  })
}

I have a file registry.ts which contains my singleton to fetch my prisma adapter (so I only have 1 connection). This is what the db() function does, it returns my database adapter (= new PrismaClient()), but YMMV.

Then simply call the fetch() function in your middleware to request this API route and get the data.