-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Can't use Prisma client in Next.js middleware, even when deploying to Node.js #21310
Comments
@markspolakovs you should try importing the prisma client like this |
Same issue here. |
@markspolakovs |
Thanks for confirming @millsp. Is this still true if I'm self-hosting my Next app (using Docker), rather than running it on Vercel? |
Hmm, I am trying to think what we could do to workaround this. Next.js is bundling your project, and it will bundle the separate edge function via the
You may get other hurdles down the line (eg. engine or schema not being copied in the correct locations), happy to assist as needed. |
Pretty annoying. Moving the very same function call out of the middleware and it works. |
Unfortunately it looks like Next's edge runtime blocks all this trickery: I tried the
(I ran It looks like it's getting tripped up on Prisma requiring 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: vercel/next.js#38989 |
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.
|
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as off-topic.
This comment was marked as off-topic.
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).
|
Vercel Edge Middleware is not a Node.js runtime, but the Vercel Edge Runtime. Prisma currently can not run in that environment as it does not allow talking to databases via the normal database drivers using the normal methods like TCP connections - which Prisma usually uses. |
@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 |
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: #21394 |
IMO this issue is about this error message appearing even and preventing usage of prisma in middleware when not using Vercel in any way, not that the prisma client can't be used in the vercel edge runtime. @janpio The original reproduction from this issue should do the trick. |
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. |
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 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): markspolakovs/next-prisma-repro#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.) |
@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! |
Stoked to have this working! However, I can no longer find a way to access a local postgres instance from the middleware. We use Neon in production, but for local development it's more convenient to use a local postgres instance. Has anyone found a workaround for this? |
Our own tests use a "proxy" from Neon in front of a PostgreSQL database, which is the same component that runs remotely as the endpoint for the Neon serverless database driver: prisma/docker/docker-compose.yml Lines 223 to 239 in 07f8b3a
|
@janpio awesome, this seems like a great approach. I can't quite get it to work, however. Running the container is simple enough, however the Are you doing anything special at Something as simple as this doesn't appear to work for me const pool = new Pool({ connectionString: 'postgresql://username:@localhost:5488/dbname' })
const adapter = new PrismaNeon(pool)
const prisma = new PrismaClient({ adapter }) This results in
|
See here @defrex: prisma/packages/client/tests/functional/_utils/setupTestSuiteClient.ts Lines 147 to 161 in b6efac2
(If you figure it out, I would appreciate a blog post so I can link to that one in the future 😆) |
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 ProxyAdd the @neondatabase/wsproxy to your In this example neon_wsproxy:
container_name: neon-wsproxy
image: ghcr.io/neondatabase/wsproxy:latest
environment:
APPEND_PORT: 'db:5432'
ALLOW_ADDR_REGEX: '.*'
LOG_TRAFFIC: 'true'
LOG_CONN_INFO: 'true'
ports:
- '5488:80'
depends_on:
- db
restart: unless-stopped
healthcheck:
test: ['CMD', 'nc', '-z', '127.0.0.1', '80']
interval: 5s
timeout: 2s
retries: 20 Then, initialize your // Polyfill for WebSocket in Node.js
if (global.WebSocket === undefined) { // don't break Edge, where `global.WebSocket` pre-exists
const ws = require('ws')
neonConfig.webSocketConstructor = ws
}
let databaseUrl = process.env.DATABASE_URL
// Configure the Neon adapter to connect to the local Neon proxy
if (databaseUrl.includes('localhost')) {
// we edit the direct `DATABASE_URL` here, so `.env` can still be used by the `prisma` CLI
databaseUrl = editDatabaseUrl(databaseUrl, { port: 5488 })
neonConfig.wsProxy = () => `127.0.0.1:5488/v1`
neonConfig.useSecureWebSocket = false
neonConfig.pipelineConnect = false
}
const pool = new Pool({ connectionString: databaseUrl })
const adapter = new PrismaNeon(pool)
const prisma = new PrismaClient({
adapter,
datasources: {
db: { url: databaseUrl },
},
}) Et voila! This |
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. |
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. |
@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: vercel/next.js#46722 Looks like Vercel has no intention of allowing self hosted middleware any time soon. |
@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. |
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. |
Here is the Next.js documentation that highlights what is causing this challenge:
https://nextjs.org/docs/app/building-your-application/routing/middleware#runtime Sorry, but as far as I know there is nothing Prisma can do about that. (We have been talking internally about if we can at least document how to set up the Neon and PlanetScale proxies for local testing.) |
Hi @janpio Thats why I am now migrating to use drizzle orm. |
Let me know if and how Drizzle has solved that problem. If they have, we have overlooked something and can work on a similar solution of course. |
Hi @markspolakovs, @bilalmohib and others, can you please retry with the following (unstable) version of We believe that such version contains the fix to this issue. |
I have found a minimal workaround for now. This is to have the prisma on a api and handling the request from there. // middleware.ts
import { NextRequest, NextResponse } from 'next/server'
import { isAuthenticated } from './lib/auth'
export const config = {
matcher: '/api/:path*',
}
export async function middleware(request: NextRequest) {
// this api has the auth related info
if (request.nextUrl.pathname.startsWith('/api/prisma')) {
return NextResponse.next()
}
// Call our authentication function to check the request
if (!(await isAuthenticated(request))) {
// Respond with JSON indicating an error message
return Response.json(
{ success: false, message: 'authentication failed' },
{ status: 401 }
)
}
} And then one api, // lib/auth.ts
import { NextRequest } from "next/server";
export async function isAuthenticated(request) {
// do stuff like checking if the user pass etc matches with the api
fetch(`${process.env.NEXTJS_APP_URL}/api/prisma`)
.then((data) => data.json())
.then(console.log);
return true;
} // /api/prisma/route.ts
// EDIT: move this to somwehere else like lib/db.ts
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient()
export async function GET(request: Request) {
const posts = await prisma.post.findMany()
return new Response(JSON.stringify(posts))
} Definitely not the prettiest solution, but still many times better than having same code/function in 10 different api files. |
Hi @entrptaher, my recommendation is to not expose Prisma to the Next.js To see how Prisma can be then used for API endpoints, you may refer e.g. to this Next.js Auth example. Regardless, the important thing for Edge Middlewares to work correctly with Prisma is to either wait for Prisma 5.15.0 (which we'll release tomorrow) or try the integration version posted above, |
Thank you for the reply. I do not use or suggest prisma from api route directly, the above example is just a proof of concept to show a workaround. |
@jkomyno I tried upgrading to 5.15.0-integration-client-dynamic-wasm-imports.1 (both prisma and prisma/client) but to no avail, currently, the only solution that works is using Prisma accelerate. |
Hey @CodeZak, can you please share your own reproduction, possibly in a new issue? I wonder whether you bumped into a different edge case than the one we have fixed. Thanks! |
Also, @CodeZak, did you re-run |
We fixed this issue via #24312, and the fix will be part of the newest Prisma version, 5.15.0, coming out today 🚀 Though I will close this issue right now, please keep the feedback coming below. Thanks! |
yeah, i did that, |
Bug description
Next.js middleware seems to fail the edge runtime check, even when deployed to Node.js:
Wasn't sure if this is a Next or a Prisma bug.
How to reproduce
yarn dev
Expected behavior
DB operations to work inside middleware.
Prisma information
Environment & setup
Prisma Version
The text was updated successfully, but these errors were encountered: