Replies: 73 comments 78 replies
-
I've been wanting the same for a while. My reading of the situation is that the problem is one of two worlds:
For those running Next in the first way, which is usually me for most projects at work, it feels pointless to have middleware be restricted to only supporting the edge runtime. Plenty of things which would logically want to be there, like managing rewrites for A/B testing, are handicapped because most 3rd parties are only providing Node SDKs for this kind of thing. For those running Next in the second way, limiting middleware to the edge runtime conceptually makes a lot of sense, because otherwise people are being handed a performance footgun. I'd be happy with edge as the default, and maybe a warning (suppressible) if you switch it to Node. |
Beta Was this translation helpful? Give feedback.
-
I'm trying desperately to do anything at all with RSCs at work, but can do nothing until Middleware can "run" in Node. And I put "run" in scare quotes since this is a self-hosted app, and middleware is already running in Node. |
Beta Was this translation helpful? Give feedback.
-
Workaround (PostgreSQL using Vercel Postgres / Neon Database)For PostgreSQL, it looks like some new packages for the upcoming Vercel Postgres service are enabling database communication in the Vercel Edge Runtime using a WebSocket-to-TCP proxy (Cloudflare blog post):
It does come with some caveats:
|
Beta Was this translation helpful? Give feedback.
-
@leerob Thanks! ✌️ |
Beta Was this translation helpful? Give feedback.
-
Alternative: Improve Node.js API support for more Capable Edge RuntimesSome non-Vercel platforms and edge runtimes mentioned below support more capabilities / APIs from Node.js. This may provide a path forward for the industry - fewer limitations on edge runtimes. More capable edge runtimes may be able to solve most of the issues that people have with edge runtimes. This may offer an alternative for Next.js Middleware - to instead add more Node.js capabilities to edge runtime environments. Deno Deploy supports Node.js builtins at the edgeDeno Deploy supports Node.js builtins as of 26 May 2023:
Source:
Cloudflare Workers TCP
|
Beta Was this translation helpful? Give feedback.
-
I encountered this problem today while attempting to use the MongoDB driver within the middleware. It has taken a while to work out what the actual problem is. I think there might be a workaround within the top-level layout module for my specific use-case but it's an unexpected and disappointing problem to run into while using Next. Being able to switch the runtime used by the middleware would be very much appreciated 👍 |
Beta Was this translation helpful? Give feedback.
-
really need this request! hope soon come |
Beta Was this translation helpful? Give feedback.
-
Ran into the same issue while trying to connect to Redis to implement an authentication flow. Our team uses middleware for a cleaner and logical code flow rather than for performance benefits. Being able to run middleware on the centralized server using the Node runtime would make using middleware much more viable for our use case. Would really appreciate if this feature could be added to the roadmap! |
Beta Was this translation helpful? Give feedback.
-
Thanks for this discussion. I was really confused. Same here. I try to authenticate a request (implementation of the authenticate function of the doc) and can't because the node crypto is unavailable. What is really strange is that it works on route handlers (api route), which I use for OAuth authentication. |
Beta Was this translation helpful? Give feedback.
-
As per this twitter discussion: https://twitter.com/AxelVaindal/status/1676581063638786048 The use case is the following:
Unfortunately, Firebase team is not considering supporting edge anytime soon, and I feel Firebase is big enough provider we should make sure to provide at least enough guidance to folks using it in production with Next.js (ideally without third party packages). A simple way to opt-out of Edge if we are self hosted, as @arackaf suggested, would be enough for us, as our middleware already runs in Node.js anyway. |
Beta Was this translation helpful? Give feedback.
-
I'm guessing the primary workaround for this, then, is to move crypto-necessary tasks (and the like) into each router handler, right? |
Beta Was this translation helpful? Give feedback.
-
Still no word from Vercel on this? Is it on their roadmap? It's very frustrating for those of us that will be self-hosting on AWS and other solutions that are not Vercel to have middleware limited to Edge runtimes. As someone above mentioned, it really does feel a bit like vendor lock-in on the part of Vercel. It's hard to know without some kind of response from the team. In our case we want to use openid-client for checking and refreshing access tokens from httpOnly cookies. Middleware is the obvious place to do this, but it would seem that the only current solution is to query an API route from our middleware. I really hope they add an experimental flag that allows us to select the runtime for middleware. |
Beta Was this translation helpful? Give feedback.
-
please make this happens, it's really crucial for some applications that really need to use other than edge-runtime-provided module like bcrypt in their middleware, i hope nextjs team would read this |
Beta Was this translation helpful? Give feedback.
-
We're continuing to evaluate the constraint for Middleware using the Edge Runtime and exploring ways to bridge the gap towards allowing folks to experimentally/"dangerously" opt-into using the Node.js Runtime. I appreciate the feedback here, but let's assume good intent and not make broad generalizations. Let me add a bit more clarity here.
We agree. While the Edge Runtime has good constraints, for code that should run potentially in front of every request in your application, those constraints also have the tradeoff of smaller compatibility with existing ecosystem libraries. While there's been a lot of progress here in the past few years since we added Middleware, there's still libraries (as well as internal packages) that do not (or will not) support running with the Edge Runtime. We hear you.
To further underscore this, it is a key design constraint of Middleware today.
Correct, since this discussion was opened, Next.js Edge Runtime now supports:
It's also worth mentioning that another path forward here today is using Server Components with the App Router. You can add async logic, like handling authentication, in the root layout which applies to all routes. This is similar to Middleware in some cases. Further, you can add that logic in a nested layout, or a route group, only applying the logic to a specific set of routes. |
Beta Was this translation helpful? Give feedback.
This comment was marked as off-topic.
This comment was marked as off-topic.
-
I was waiting for some time if this gets addressed as I needed to access Vault for some session encryption keys, which couldn't be done in Edge runtime. But since i had to move on with the project, i reverted to a workaround - posting it here as it might help someone: I'm on v14.x , using app directory, so i refactored all of the route handlers to use access wrappers: // pageAccess.ts
export type RouteHandlerContext = { params: {[key: string]:string }, userId: number, someExtraData: ExtraDataModel }
export function withAccess(fn: any) {
return async function (request: Request, context: RouteHandlerContext) {
const res = NextResponse.next();
const session = await getIronSession(request, res, ironOptions);
// add any custom logic
if (!Object.keys(session).length) {
return forceLogoutResponse()
} else {
context.userId = Number(session.userId);
return await fn(request, context);
}
}
}
export function withElevatedAccess(fn: any) {
return async function (request: Request, context: RouteHandlerContext) {
const wrappedFn = withAccess(async (request: Request, context: RouteHandlerContext) => {
// add any custom logic
context.someExtraData = await getExtraData();
return await fn(request, context);
})
return await wrappedFn(request, context)
}
} I refactored all my routes (hundreds in my case..) as follows: // route.ts
export const GET = withAccess(
async (req: Request, { userId }: RouteHandlerContext) => {
// ...handler code
})
export const POST = withElevatedAccess(
async (req: Request, { userId, someExtraData }: RouteHandlerContext) => {
// ...handler code
}) This allowed me to move anything i was doing in middleware to move into the wrapper, with extra bonus of getting more granularity on access control (i have multiple levels, and the logic handled in middleware was growing) For the UI part i used very similar approach, using a PageWrapper component for all the pages (luckily i had this in place from the beginning since i am injecting i18n messages and some other props): // PageWrapper.tsx
export default async function PageWrapper({ children, headerTitle, messages }: Props) {
// do your stuff
await doCommonChecks();
return (
<NextIntlClientProviderWrapper messages={{ ...messages }} >
<SubHeader title={headerTitle}/>
<div className="container">
{children}
</div>
</NextIntlClientProviderWrapper>
);
} and finally, all the page.tsx files use the wrapper: // page.tsx
export default function SomePage() {
const messages = useMessages();
return (
<PageWrapper headerTitle="SomePage.___header_title" messages={{
SomePage: messages?.SomePage as AbstractIntlMessages
}}>
<SomePageContent/>
</PageWrapper>
)
} |
Beta Was this translation helpful? Give feedback.
This comment was marked as off-topic.
This comment was marked as off-topic.
-
The one solution I'm currently using is to:
This I know it's not ideal, but at least it's something |
Beta Was this translation helpful? Give feedback.
-
Fuck it. I already have a express server infront of my Next.js App. So I just did the middleware at the express level and I love it. |
Beta Was this translation helpful? Give feedback.
-
@rickitan when I try putting an express server infront of a Next.js app, the websocket breaks for hot reloading in development. How do you get around this? |
Beta Was this translation helpful? Give feedback.
-
Fuck it, I'm switching to Express. I just want to roll a self hosted server. Is that so much to ask? Do we really need to be locked into edge functions? This thread has been open over a year and yet no update from the Vercel team. I am trying to use Next.js middleware + Prisma to validate user sessions. But apparently this requires edge functions + Prisma Accelerate (both of which cost money). There is NO way to self host when using middleware. What kind of f**ked up design choice is that? Self hosting prohibited? Give me a break. I'm not too keen on the idea of building a proxy server just to handle middleware. So I'm leaving. Bye Bye Nextjs. |
Beta Was this translation helpful? Give feedback.
-
If anyone is interested in collaborating on a fork of Next.js that is more open and not vendor locked, feel free to submit PRs to unlocked-next/unlocked-next.js (totally new, no changes yet). Goals:
Forking and decentralization is how open source moves forward. |
Beta Was this translation helpful? Give feedback.
-
I wanted to do a simple thing: After user sign in (next-auth v5) if his profile is not complete, then just always redirect him to /finalize, and I can't due to moongose not working on edge and unability to disable edge for middleware. That sucks :/ |
Beta Was this translation helpful? Give feedback.
-
I don't want this to go stale, so bumping. |
Beta Was this translation helpful? Give feedback.
-
Relevant tweet from @leerob describing how/why vercel chose to move all rendering for their own next.js app to Node.js runtime instead of edge for performance and ecosystem reasons: link Basically backpedalling a bunch of value props used to shill edge runtime due to reasons that have been obvious to everyone in this thread for over a year now! |
Beta Was this translation helpful? Give feedback.
-
Update from X/Twitter@leerob voices support for "route level middleware", which would run in the render process - from my understanding, this would be a non-edge runtime environment:
Source: https://twitter.com/leeerob/status/1780716511797088359 |
Beta Was this translation helpful? Give feedback.
-
While I support addition of route level middleware because it might be something interesting and useful, I propose improvement of existing middleware. |
Beta Was this translation helpful? Give feedback.
-
Aaaaaand Next 15 does NOT change this, GREAT JOB |
Beta Was this translation helpful? Give feedback.
-
It's clear the nextjs team is focused on their ecosystem and isn't interested in integrations outside of it. I'm probably going to switch to vite over concerns regarding the future of nextjs. This is what happens when VCs control the direction of a project instead of developers controlling the direction. |
Beta Was this translation helpful? Give feedback.
-
You can always edit the webpack plugin file that has a whitelist for allowed node libs (events, buffer etc ). If running on node, of course they will work just fine. The changes to make this configurable officially are so minimal that it's hard to understand all this. |
Beta Was this translation helpful? Give feedback.
-
Goals
fs
,net
andtls
to perform database queries withoutfetch
overhead)experimental.runtime = 'nodejs'
does not work for MiddlewareBasically to allow for checking this last box at the bottom right (thanks for the idea for the diagram @thescientist13)
Non-Goals
Use Cases
Redirect logged out users
Middleware for multiple protected app routes to:
sessionToken
cookiefetch
overhead) 👈 currently not possible without overheadSet-Cookie
header to delete invalidsessionToken
cookie/login
It is point 2 "Query PostgreSQL..." that is currently not possible without overhead. Let's examine the overhead:
With
edge
runtimefetch
required, with HTTP overheadAPI_BASE_URL
/api/users/current
).env.*
middleware.ts
app/api/users/current/route.ts
database/users.ts
With
nodejs
runtimemiddleware.ts
database/users.ts
Background
Examples of confusion
Proposal
Middlewares should have a flag
experimental.runtime
(similar to the RFC posted by @shuding ), which can also be set to the value'nodejs'
Beta Was this translation helpful? Give feedback.
All reactions