prisma: Can't use Prisma client in Next.js middleware, even when deploying to Node.js
Bug description
Next.js middleware seems to fail the edge runtime check, even when deployed to Node.js:
Error: PrismaClient is unable to run in Vercel Edge Functions. As an alternative, try Accelerate: https://pris.ly/d/accelerate.
If this is unexpected, please open an issue: https://github.com/prisma/prisma/issues
Wasn’t sure if this is a Next or a Prisma bug.
How to reproduce
- Clone https://github.com/markspolakovs/next-prisma-repro
- Run
yarn dev
- Visit http://localhost:3000
Expected behavior
DB operations to work inside middleware.
Prisma information
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
}
import { PrismaClient } from "@prisma/client";
import { NextRequest, NextResponse } from "next/server";
const prisma = new PrismaClient();
export async function middleware(req: NextRequest): Promise<NextResponse> {
const user = await prisma.user.findFirst();
return NextResponse.next();
}
Environment & setup
- OS: macOS arm64
- Database: SQLite
- Node.js version: v18.17.0
Prisma Version
prisma : 5.3.1
@prisma/client : 5.3.1
Current platform : darwin-arm64
Query Engine (Node-API) : libquery-engine 61e140623197a131c2a6189271ffee05a7aa9a59 (at node_modules/@prisma/engines/libquery_engine-darwin-arm64.dylib.node)
Schema Engine : schema-engine-cli 61e140623197a131c2a6189271ffee05a7aa9a59 (at node_modules/@prisma/engines/schema-engine-darwin-arm64)
Schema Wasm : @prisma/prisma-schema-wasm 5.3.1-2.61e140623197a131c2a6189271ffee05a7aa9a59
Default Engines Hash : 61e140623197a131c2a6189271ffee05a7aa9a59
Studio : 0.494.0
About this issue
- Original URL
- State: open
- Created 9 months ago
- Reactions: 14
- Comments: 31 (10 by maintainers)
A solution for anyone else who ran into this error just trying to set up a project - I believe you can just use jwt sessions, rather than database sessions.
Fortunately, we just released Prisma ORM version 5.11.0 which includes a preview feature for Edge Functions support for Vercel Edge Functions and Middleware (and Cloudflare Workers and Pages) in Prisma ORM 🥳
Please give it a try, and let us know how it goes! If you encounter any problems, please create a new bug report issue, or if the problem is driver adapter specific, use the feedback discussions for
@prisma/adapter-neon
,@prisma/adapter-planetscale
, or@prisma/adapter-libsql
/ Turso 🙇With that I was able to upgrade the reproduction from the original issue description to Prisma 5.11.0, and use a PostgreSQL database from Neon (or Vercel Postgres): https://github.com/markspolakovs/next-prisma-repro/pull/1 (Unfortunately the Edge Runtime does not support reading local files, so using SQLite - which is a local file - is out of the question, so I had to switch to using PostgreSQL.)
This is very annoying, I dont use Neon or Planetscale, or even Vercel or Cloudflare edge functions.
I just want to roll my own middleware and my own database on my own server. It makes no sense why I cant just invoke the client locally. Why do we have to use a special Neon adapter or have a cloudflare account or use Accelerate? Why cant we just invoke local stuff in our middleware? This makes no sense. Overengineered garbanzo.
@janpio Might be true, but that is not a relevant fact in my case since I don’t use Vercel. I deploy Next.js apps as Docker containers that run in Kubernetes. The base Docker image is always
node:21-alpine
.Why would querying the DB be any different in middleware than in a server component? To the DB client, it’s all just a Node.js runtime.
I hope I’m wrong, but this seems like a deliberate limitation to sell some commercial feature. Which is really outside the spirit and ethos of open source (see OSI).
Pretty annoying. Moving the very same function call out of the middleware and it works. This was my workaround for now, but I would have preferred to keep the code in the middleware where it was before we started using Primsa. 🙈
@defrex
Respectfully you are mistaken. This problem was created from the decision to redefine middleware as “edge middleware” which is a complete deviation of what “middleware” means in the context of a web framework. Vercel has decided to lock a basic feature of web frameworks (middleware that is executed before/after a request) behind a vendor-specific implementation. It’s like a scope creep that omits the original feature.
If there was “edge middleware” and regular middleware, than this entire thread would not exist. If they had released only “Edge Middleware” than this Github Issue would be a Feature Request to “Add normal middleware” instead of a bug because we wouldn’t have a false expectation. I’m using the term “middleware” as its conventionally used in Nest.js, Django, Laravel, Rails and other frameworks.
I’m happy to report this strategy worked! I don’t know about dusting off the blog, but here is a quick summary for future travellers.
Local Neon-Enumating Websocket Proxy
Add the @neondatabase/wsproxy to your
docker-compose.yaml
.In this example
db
is the name of my postgres container, swap it out for your own!Then, initialize your
PrismaClient
andPrismaNeon
adapter with a few extra touches.Et voila! This
prisma
instance shout be GTG for use in the Edge runtime, with either a local or Neon-hosted postgres instance.@petercunha @iMerica I can’t speak to the business motivations here (I don’t work for Vercel or Prisma), but there is an actual technical issues at play.
Middleware runs on an Edge runtime, same as Cloudflare Workers. I suspect this choice was made for performance reasons. Ie if you’re going to run a separate process before every request, you’d better make it a fast one. But by separating the process out, you can serve static or cached assets to the client, without needing to make a full server-render run. Otherwise Next.js with auth would have similar perf characteristics to Rails or Django.
However, the Edge runtime only has access to web-standard APIs, without any Node.js extensions. This means it can’t use unix sockets or tcp to connect to the database. That leaves HTTP or WebSockets. The request/response overhead makes using HTTP prohibitive.
Neon and Planetscale both support WebSocket connections out of the box, which is why they can be supported. The code above shows how you can use a proxy service to allow a WebSocket connection to a regular Postgres instance, this could easily be used in production if you’re willing & able to run that container.
@petercunha
As far as I can tell this issue was a product decision made by Vercel. It seems like they have completely lost the plot – forgetting that they are the stewards of an open source project web framework (Next.js) - not a Vendor web framework called Vercel.js. It’s not over-engineered, it’s wrongfully engineered.
If it was “open” this middleware would be interoperable in any cloud/server environment instead of exclusively on Vercel. Sadly, Next.js is becoming fauxpen source.
@janpio Thanks for the update, instructions, and the example PR!
I upgraded prisma in my project and was also able to use prisma via the neon adapater in my middleware function…slick!
i can confirm that adding
session: { strategy: "jwt" }
is working for me, i’m not sure why people gave thumbs downUnfortunately it looks like Next’s edge runtime blocks all this trickery: I tried the
client/index
import that @millsp suggested, and also setunstable_allowDynamic
in my middleware config, but Prisma Client still fails to load:(I ran
runtime/library.js
through prettier to help with debugging, hence the line numbers being different.)It looks like it’s getting tripped up on Prisma requiring
debug
which then requires Node’sutil
module to callutil.deprecate
- unfortunately I’d imagine that trying to solve this will just lead to a game of whack-a-mole with various Node modules the Edge Runtime doesn’t support.I found a feature request on the Next side to allow configuring middleware to use the Node runtime, but with no response from the Next team: https://github.com/vercel/next.js/discussions/38989
@iMerica you are correct. I thought this was Prisma’s fault at first, but it turns out that edge middleware is a vendor lock in strategy by Vercel.
Unfortunately the only way around this is to build a proxy server in front of Next.js that handles middleware.
There is a thread about this on Next’s repo that has been open for over a year with no updates: https://github.com/vercel/next.js/discussions/46722
Looks like Vercel has no intention of allowing self hosted middleware any time soon.
The Next.js documentation has the answer to the problem:
Source https://nextjs.org/docs/app/building-your-application/routing/middleware#runtime
So even when you run your Next.js app locally via Node.js, it unfortunately still runs the middleware via the Edge middleware instead.
Then you should open a bug report instead of assuming ill intent, so we can look into that, because that of course should not happen. Obviously the error message is incorrect, and we want to look into that and fix it. (I am not fully sure if that is also the case above, so an additional bug issue with information and optimally a reproduction would be very helpful.)
PS: We are also currently working on, and have a private Early Access running, for support of Vercel Edge Middleware: https://github.com/prisma/prisma/issues/21394