| ▲ | Rauchg 5 days ago |
| Heard and appreciate the feedback. We’re well aware of the DX papercuts in Middleware. With 15.5 we made a big step in supporting Node runtime[1] which addresses a slew of issues people have reported over time. If I went back in time, I would have called it Routing Middleware or Routing Handler. A specific hook to intercept during the routing phase, which can be delivered to the CDN edge for specialized providers. It’s also a somewhat advanced escape hatch. Since OP mentions logging, it’s worth noting that for instrumentation and observability we’ve embraced OpenTelemetry and have an instrumentation.ts convention[2] [1] https://nextjs.org/blog/next-15-5#nodejs-middleware-stable [2] https://nextjs.org/docs/app/api-reference/file-conventions/i... |
|
| ▲ | throwaway150 5 days ago | parent | next [-] |
| Appreciate the response. But ... > Since OP mentions logging, it’s worth noting that for instrumentation and observability we’ve embraced OpenTelemetry and have an instrumentation.ts convention That makes it sound as though the answer to a clumsy logging facility is simply to add another heavy layer of complexity. Surely not every application needs OpenTelemetry. Why can’t logger().info() just work in a sensible way? This can't be such a hard problem, can it? Every other language and framework does it! |
| |
| ▲ | conor- 5 days ago | parent [-] | | > Why can’t logger().info() just work in a sensible way? I think OTEL is pretty sensible for a vendor-free and if you want to have a console logger you can use the console exporter[0] for debug mode during local development. Also if Next is designed as a framework to make it easy to build production-grade apps, having a standardized way to implement o11y with OTEL is a worthwhile tradeoff? If you view that as being overkill, perhaps you're not the target audience of the framework [0] https://opentelemetry.io/docs/languages/js/exporters/#consol... | | |
| ▲ | specialp 5 days ago | parent | next [-] | | Because making it easy to run and monitor NextJS is never in their interest. The difficulty of that is what pushes people that make it to production with Next onto their platform. The goal is to provide more impressive preoptimizations that complicate the stack more and make it more difficult to run NextJS yourself and actually use any of them. | | |
| ▲ | conor- 4 days ago | parent [-] | | I don't really know anything about self-hosting Next apps - but if you're deploying to k8s, it's not really that difficult or far-fetched to run an otel collector sidecar for your applications. It's already common to run some kind of prometheus scraper or other service to collect logs/metrics from your services but instead of having to have different collection methods for APM vs logs vs traces you can have it all aggregated in one place using OTLP format | | |
| ▲ | camdenreslink 3 days ago | parent [-] | | Just by bringing up k8s you are making their point. It should be dead simple to do logging without having to set up hardly anything. I shouldn't even need to know what a sidecar container is. | | |
| ▲ | conor- 3 days ago | parent [-] | | "dead simple" really depends on what you're targeting and how. If you're targeting a cloud deployment on hardware you don't control or that's running with multiple instances/replicas, OTEL makes that pretty simple because you get a lot for free in the way of tracking instances/correlation ids, etc. If you wanted "dead simple" text-based logging in a situation where a service is deployed in multiple places you'd end up writing a lot of fluff to get the same log correlation abilities that most OTEL drivers provide (if you can even ship your logs off the compute to begin with) Which again comes back to the "maybe the framework isn't for you" if you're building an application that's a monolith deployed on a single VPC somewhere. But situations where you're working on something distributed or replicated, OTEL is pretty simple to use compared to past vendor-specific alternatives |
|
|
| |
| ▲ | tacker2000 5 days ago | parent | prev [-] | | Again, why would one need such a heavyweight tool? Most frameworks have powerful loggers out of the box, like Monolog in the PHP world. | | |
| ▲ | conor- 5 days ago | parent [-] | | What specifically is heavyweight about OTEL? At its core it's a standard for producing structured logs along with some standards for exporting/collection. The heaviness is really implementation-specific and can vary stack to stack There's even a handler for monolog in PHP - they are not necessarily mutually exclusive https://github.com/open-telemetry/opentelemetry-php/blob/mai... | | |
| ▲ | tacker2000 4 days ago | parent [-] | | Yes but instead of just logging to a text file for example you need OTEL, thats my point. The fact that Monolog has a handler for this tool isnt relevant, but it shows that there is one more layer of complexity tacked on. | | |
| ▲ | conor- 4 days ago | parent [-] | | That doesn't really mean it's heavyweight though; an extra layer, sure (but I don't even really agree that it's complex - you set it up once and then mostly just log the same way you would with any other). You can still log to a text file if you want to run locally, but for something like next.js where you're intended to deploy production to some cloud somewhere (probably serverless) the option of _just_ writing to a text file doesn't really exist. So having OTEL as an ootb supported way to do o11y is much better than the alternative of getting sucked into some vendor-specific garbage like datadog or newrelic |
|
|
|
|
|
|
| ▲ | arnorhs 5 days ago | parent | prev | next [-] |
| First off, since the sentiment here is really negative, I'd like to say that next.js is actually really good for what it does. You've done a great job at building the software that powers millions of websites at this point. I think a big part of the negative sentiment derives from the fact that detailed documentation and reference documentation almost non-existant. The documentation mostly tells you what exists, but not how to use them, how they get executed, common pitfalls and gotchas etc etc. The documentation is written to be easy and friendly to newcomers, but is really missing the details and nuances of whatever execution context a given api is in and does not touch on derived complexities of using react in a server environment etc. This is a trend across a lot of projects these days - often missing all the nuances and details - writing good documentation is really hard. Finding the balance between making things user friendly and detailed is hard. Keep it up |
| |
| ▲ | icyJoseph 5 days ago | parent | next [-] | | > Finding the balance between making things user friendly and detailed is hard. Thanks for the note! Indeed, it is also challenging when experience hides what things are not obvious or necessary to make further connections when reading the docs. It is an area of continuous improvement. > The documentation is written to be easy and friendly to newcomers, but is really missing the details and nuances of whatever execution context a given api is in and does not touch on derived complexities of using react in a server environment etc. I think on this particular topic, there had been an assumption made on the docs side, that, listing Edge runtime (when middleware was introduced), as its own thing, that might as well run in another computer, would also communicate that it does not share the same global environment as the underlying rendering server. I'll do some updates to narrow this down again. > The documentation mostly tells you what exists, but not how to use them, how they get executed, common pitfalls and gotchas etc etc. Do you have anymore examples on this. I have been improving the revalidateTags/ Paths, layouts, fetch, hooks like useSearchParams, gotchas with Response.next, etc.. I know the OP post does talk about issues not being responded to, but that trend has been changing. If you do find/remember something as you describe, please do open a documentation issue, pointing to the docs page and the confusion/gotcha - we have been addressing these over the past months. | |
| ▲ | mhitza 5 days ago | parent | prev [-] | | Don't you find it problematic, as a framework that's 8 years old to already have reached version 15.x? Assuming they follow semantic versioning and those are 15 different backwards incompatible upgrades? | | |
| ▲ | Vinnl 5 days ago | parent | next [-] | | Most of our upgrades have been fairly painless. Yes, they're not CI-succeeds Dependabot merges, but usually it's basically running the auto codemod and you're done, though I do always scan through the release notes and migration guide. That seems justified for the backbone of our application. | |
| ▲ | conradkay 5 days ago | parent | prev | next [-] | | I haven't used next.js but it looks like they have mostly automatic/codemod migrations `npx @next/codemod@canary upgrade latest` | | |
| ▲ | arnorhs 4 days ago | parent [-] | | Yes, those have been really decent IIRC - don't remember ever having issues upgrading |
| |
| ▲ | presentation 5 days ago | parent | prev [-] | | Don’t think it’s semver. | | |
| ▲ | brazukadev 5 days ago | parent [-] | | I think it is, that is why it is still unstable, 2 majors changes/year. |
|
|
|
|
| ▲ | bestest 5 days ago | parent | prev | next [-] |
| Since you're here — I'll just pipe in. Here in this article, the author, failing to comprehend the domain differences, is applying the same approach to call a function everywhere. Of course it won't work. The fallacy of nextjs is attempting to blend function domains that are inherently different. Stop doing that and you will be fine. Documentation won't work, it will be just more confusing. Blending edge and ssr and node and client-side into one is a mess, and the attempt to achieve that only results in layers upon layers of redundant framework complexity. |
| |
| ▲ | presentation 5 days ago | parent [-] | | Sounds like you wouldn’t be a fan of React Server Components in general then since blending domains is its whole point. | | |
| ▲ | hungryhobbit 5 days ago | parent [-] | | Blending domains is great. Blending domains where you don't get logging at some levels because your framework is incompetent is not. |
|
|
|
| ▲ | dminik 5 days ago | parent | prev | next [-] |
| Yeah, I was actually recommended the instrumentation route by a commenter on Reddit. I spent a similar amount of time setting up opentelemetry with Next and while it would have been titled differently, I would have likely still written a blog post after this experience too. This isn't your fault, but basically every opentelemetry package I had to setup is marked as experimental. This does not build confidence when pushing stuff to production. Then, for the longest time I couldn't get the pino instrumentation working. I managed to figure it out eventually, but it was a pain. First, pino has to be added to serverExternalPackages. If it's not, the OTel instrumentation does not work. Second, the automatic instrumentation is extremely allergic to import order. And also for whatever reason, only the pino default export is instrumented. Again, this took a while to figure out. Module local variables don't work how I would expect. I had to use globalThis instead. And after all that I was still hit by this: https://github.com/vercel/next.js/issues/80445 It does work, but it was not great to set up. Granted, I went with the manual router (eg. not using vercel/otel). |
|
| ▲ | rozumbrada 5 days ago | parent | prev | next [-] |
| If you finally decided to support proper server-side middleware, why is there still a limitation for only one middleware function and not a chain of middleewares as every other sane server implementation offers? |
| |
| ▲ | bestest 5 days ago | parent [-] | | Consider middleware.ts as a root middleware. Nothing is stopping you from creating your own chain (which is trivial) in there. I mean, that would eventually work the same if nextjs implemented that feature — there would be a root somewhere. | | |
| ▲ | rs186 5 days ago | parent [-] | | That doesn't answer parent's question. People expect "middleware" to mean a certain thing and work a certain way. | | |
| ▲ | bestest 5 days ago | parent [-] | | middleware = fn(req) → next(req).
express/koa give you the use() chain.
next.js gives you one root, but nothing stops you from chaining yourself. same semantics, just manual wiring. type mw = (req: Request, next: () => Response) => Response;
const logger: mw = (req, next) => {
console.log(req.url);
return next();
}; const auth: mw = (req, next) => {
if (!req.headers.get("x-auth")) return new Response("forbidden", { status: 403 });
return next();
};
function chain(mws: mw[]) {
return (req: Request) =>
mws.reduceRight((next, mw) => () => mw(req, next), () => new Response("ok"))();
}
export function middleware(req: Request) {
return chain([logger, auth])(req);
}
root is given, chain is trivial. that’s middleware. | | |
| ▲ | rafaelmn 5 days ago | parent [-] | | Nothing trivial about that implementation in my mind - need to keep track of where middleware is registered, reduceRight is non obvious. I expect these things to be standardized by the framework and all the sharp edges filed off - thats why I go to a framework in the first place. | | |
| ▲ | foldr 5 days ago | parent [-] | | The reduceRight is just a bit of cute FP code golf. All it’s saying is that chaining an empty list of middleware yields an ‘OK’ response, and that the first middleware is passed a function which, when called, executes the remaining middleware chain, and so on. It would be obvious enough if written out as a for loop, or via direct recursion. (My username has never been more appropriate!) |
|
|
|
|
|
|
| ▲ | matt-p 5 days ago | parent | prev | next [-] |
| Will vercel/next come up with an official policy on pages roter/API routes, will they be supported long term? If I start a next project I still use pages/API routes, because of several really really bad experiences with the app router. |
|
| ▲ | RadiozRadioz 5 days ago | parent | prev | next [-] |
| > Since OP mentions logging [...] we’ve embraced OpenTelemetry I really hate this stuff. Users raise feedback for something they need, the dev team considers the feedback, they spend a really long time thinking about the most perfect abstraction, scope the problem way out to some big fundamental system, and come up with an extremely complicated solution that is "best". The purist committee-approved solution could technically be used to address what the user asked for, with a lot of work, but that's no longer the focus. Pragmatism goes out the window; it's all about inventing fun abstract puzzles. All the while, the user just wanted to log things. Not saying that's the exact situation here, but the phrasing in the comment was all too real to me. |
|
| ▲ | n2h4 5 days ago | parent | prev [-] |
| [dead] |