Next.js App Router migration: The good, the bad, and the ugly with Brandon Bayer === [00:00:00] Hi, and welcome to PodRocket, a web development podcast brought to you by LogRocket. LogRocket helps software teams improve user experience with session replay, air tracking, and product analytics. Try it free at logrocket. com. I'm Tejas and today we have Brandon Bayer, CEO, co founder of Flight Control and Blitz. js lead, personal friend of mine. And he's here to talk about Next. js app router migration. He wrote a blog post recently about migrating from and to the app router, the good, the bad and the ugly. So we're going to go into the details of that. Brandon, welcome to the show. It's good to be here again. Yeah, I'm so excited to chat with you. It's been so long since we've chatted. We often bump into each other at conferences and. I miss you, man. And especially, I tell you what, the people at that conference, they missed you a lot. People like Clark Sell and James Quick and the regular crew. Can you maybe give us a quick overview of flight control? First off, ~I think it's important. ~What even is that? I think it's important for the listeners to know. And then. The experience of migrating its console or dashboard from pages to the app router and why you went down that [00:01:00] path. Flight control enables engineers to easily understand and manage AWS infrastructure. And the reason here is that traditional platforms as a service like Heroku and render railway, et cetera, are really easy to use, but you always inevitably hit limitations in high cost as you scale the longterm scalable solution has always been AWS. And, but it was just, too hard in many cases and we wanted to really change that. And so flight control connects to your AWS account and enables you to easily understand and manage it and really get a really seamless developer experience. ~Okay. Okay.~ Okay. fly. io? Cause I know a number of companies do the same thing. They give you a nice developer experience on top of AWS. I guess the only difference is. You log in with accounts on those platforms and then are billed on those accounts. And so there's this like separation between platform one and platform two. Platform one being the abstraction on [00:02:00] AWS, platform two being AWS itself. And it sounds like with flight control, that separation doesn't exist. It's just, everything's AWS. You pay AWS. You just get a nicer console on top of it. Is that close? Yeah. So fly is a little bit different because they are, they're creating their own infrastructure. But for something like render a railway, it's a complete abstraction over AWS. And so from that perspective, it's a black box. You don't know what's going on under the hood. You can't inspect it, see it, own it. But with flight control, it's not a black box. It's very clear. You own the infrastructure in your account. You can go in and see what's happening. You can easily integrate with other things that you have in AWS. And so it's working really well to really power early startups to get started and then all the way up to large enterprises to move very fast. ~Okay.~ That is so cool. Okay, so flight control has this. There's a database dashboard, which I'm assuming now that we know what the product is, ~you, ~we can all visualize it something like a list or a grid or something of various AWS services that you [00:03:00] manage things like RDS, Fargate, EC2, whatever it may be. For those unfamiliar with AWS, that's just a database service and a way of running like containers and VMs being virtual machines. out So there's a dashboard that shows you maybe you're running services. How active things are, what your bills are, I assume there's some type of user profile management. It's just a typical dashboard and this was built originally in your blog post you mentioned with Next. js using the pages router and then you'll Migrate it to the app router the new, server component full way. Could you speak to that? Maybe start with why? And then we can get into how the experience was. I've been in the Next. js ecosystem for a long time. If you remember me from the Blitz. js days my goal with Blitz. js was to create a Ruby on Rails style experience for JavaScript and Next. js was the leading framework. It was really the only framework at the time. ~Like it was ~before Remix even existed. And so I'm very familiar with that. And so it was the default choice, when starting flight control and building it, of [00:04:00] course it was Next. js plus Blitz. It worked really well for a while. But the UI that I designed, I'm an engineer and I designed it. And so it looks, more like a prototype kind of thing, not like winning any design awards. ~And so let's see, ~we were about almost ~getting ~two years into the company where Okay. It's time to~ or maybe a year and a half it's ~time ~to, ~to get a real designer and like really make this thing look good. ~And ~so we partnered with an agency out of Berlin called overnice. They did a fantastic job ~designing~ designing our brand new marketing website and new dashboard. ~but as part of that~ part of that design required nested pages or nested layouts because there's a lot of complexity with infrastructure. You have projects, environments, services, and then services have configuration. They have logging and environment variables. And we created this concept where you have a side panel that comes in. ~And you,~ so you can see the main environment in the center of your screen. And then on the right side, this [00:05:00] panel slides in to see~ like~ details about a service or a deployment. And so we want that to all be URL driven. So you can easily, navigate directly to that. You can share the link that requires nested layouts and the pages router did not support that. And we needed to find a new solution. ~And~ so we evaluated a couple of different things. Mainly Next. js AppRouter or TanStackRouter. So TanStackRouter is pretty new. And at the time that we were evaluating it, it was like pre release basically, it was ~like ~early alpha and there was like stuff not working and it wasn't clear like, was it actually going to even ship? It was just too risky. We briefly considered remix but that would have switching to remix would have had to, we would have had to replace blitz or change the blitz somehow for the authentication and the RPC stuff. and next year I was at server components. ~It's ~it seems like it's a future. And so we were like let's try that. ~The~ I have to push [00:06:00] back a little bit here and wonder, did you need nested layout? Because that use case you mentioned, yes, It lends itself perfectly to nested layouts. And if you're using a framework where nested layout is a key feature, then awesome. But if not, like if you're just using, um, gosh, create React app or Vite or something, and a requirement like that arises, there's other ways you can go about adding that without while still being URL driven and also like lazy loading the appropriate fly in, etc. ~Is it the comp,~ I suppose then it's just not just that you needed nested layout, but it's the combination of that plus the futuristic server component approach. Plus you already had something with Next. js working nicely with Blitz as well. So all of these things combined to say, you know what, let's just bite the bullet and go with the new app router. And since pages router is like the old thing, that eventually it's going to go away. ~So if you're like,~ we were already doing a rewrite basically from scratch because the design is so different than the old design. And so we were like it doesn't make sense to build something [00:07:00] new on the old thing that is probably gonna go away. Interesting. Yeah, I'd be interested to talk a little bit more about why Remix wouldn't play nice with Blitz. You mentioned some of the RPC things. Can we get a little bit more into the details of that? ~I'm asking as a,~ I just, as of yesterday, decided to be more Remix forward than Next. js forward for reasons we can maybe get into at a later time. But yeah, I'd love to hear more about that, mainly so that me and the listeners considering moving to Remix ~may, ~may have these at the top of the mind. Yep. I think the main thing would be the authentication. right now the Blitz authentication, is mainly built around the Node. js request response model which You know, Next. js used to have, and not the web standard Of ~request, like the~ ~Yeah.~ request and response like Remix has like the worker style API or whatever. And so it would, we would have to change that. We ended up building an adapter so that it works with app router. maybe that would work with Remix, [00:08:00] but there's also things like How we manage the session context on the server during the request. ~Um, ~It would just be some work, like we could do it. But it'd be extra work on the BlitzRPC side. That is like very tightly coupled to Next. js. but I think a lot of that could be replaced with the Next. js. Like actions, like they're built in data loader stuff. So I think Blitz, like Blitz RPC doesn't really make that much sense in the remix land because Essentially built in already, that, would require like ~a new~ our team to learn that it was new experience. Like all the utilities and patterns that we've already built, like they have to be rewritten. yeah, and relearned and re acclimated too. Yeah, I totally see that. Awesome. Thank you for sharing that. Okay, so you then moved to the AppRouter to say, hey, let's try it. We're doing everything new anyway. ~What were the, how, ~what were the initial impressions? Was it, ~was ~the same as with me and the broader community of, Oh, this is vastly different. ~There's new, ~you just mentioned literally just now Oh, we have to learn these new things and [00:09:00] these new patterns. And it, for me, it makes sense going from next 12 to 13 with the pages to app writer, ~cause that is a. ~It's breaking in so many ways, right? It breaks the mental model, it breaks the way we would reason about layout, it breaks our preconceived notions of server rendering where it's more granular now, you have server components. Yeah, I'm just curious, what were your initial and your team's initial impressions as you dipped your toes into the water and went more and more? I did the initial sort of prototype, checking out the app router and like testing the layouts that we needed. And, It felt really good at the beginning. And really it's funny because this sort of complex routing is what we had in the early days of react with the old, like react router and single page app stuff. And then next JS with pages router, took all of that away. And now he got it back. It's ~Oh, ~like this is a new thing. Actually. It's an old thing that we just got back. But yeah, so it seemed really promising the server components. Approach, seem like a good way to load data, seem pretty easy. and I think it like, [00:10:00] I wasn't the one primarily building this. The rest of the team was actually ~a ~responsible and hands on building it. But it didn't take too long before we had started having lots of problems around the developer experience where the dev server was just became extremely slow. And has a memory leak, like it still does to this day. And you have to restart the dev server around every 20 minutes or so, depending on how many changes you're making. And so that, that's been like one of the biggest headaches by far. Interesting. So some positives, some negatives, I was in a discussion yesterday with, I think a mutual friend of ours with Kent Dodds. And we were talking about spinners and how there sometimes seems to be this movement of we don't want any spinners in our app. We don't want any skeleton UI. So we're going to do everything on the server and then just stream the responses, the pre baked, templates as it were. I once had a project. It's very similar to what you're talking about here with moving the dashboard over. And one of the requirements was, the product people said, Hey, it would be cool if the users never see a spinner. Okay. And so we said, fine, we'll move everything to [00:11:00] the server. We'll use server side layout, server components and do all of that. And indeed, we didn't have any spinners, but for some reason or the other, usually because of the client's network conditions, there were no spinners, but there was also no UI. And the favicon was the spinner, ~like right next to the,~ in Chrome next to the title. And so what we had realized as a team was, oh, we just moved the spinner. We moved the spinner from instant feedback in the UI on the client side to the server side, but the wait time is pretty much the same. I think you mentioned something to that effect in your article. You talk about loading states and its impact on user experience and developer experience. Maybe you could elaborate on that in light of this context. So this is definitely ~one of the, ~one of the benefits of the new operator and really suspense in general, like that's it's really a suspense thing as you have a lot more flexibility around. The loading States. And ~you have, you, ~you have this trade off that you've really alluded to full server side rendering, where you don't show the user any UI until everything is rendered. Or you can show a skeleton very quickly because it's [00:12:00] static and then load the data dynamic data on the client, or nowadays you can, ~you ~basically stream that still from the server, ~and. ~Like theoretically the server side approach should show complete UI quicker than when you're doing it on the client. because you have ~like ~less round trips, but in practice like I just have not seen. ~I've not seen that, ~that result. Like maybe there's some milliseconds difference. I don't know, but like perceptively our new app actually seems a little bit slower than the old one, which maybe it's because I think we are doing some more data loading and things that we should optimize. So yeah. Yeah. Thanks for that. So what I'm hearing is, your experience with next JS with the app router gave you more control over what you show the user and when I agree, I think that was also really cool ~to, ~to show a skip~ a skip was it~ One of the things with the new suspense stuff is that you can show a spinner on the old UI~ before ~before you navigate. So in the old way before suspense was like, you would click a link [00:13:00] and then the UI would change and you would see a spinner. And then the new data will load. But now if you use the use transition hook, and I talk about this in my blog post, then you can show a spinner on the old UI. So for example, we do this in our left sidebar with environment. So if you click on a different environment, Then we show a little spinner on that link. And so you're still viewing useful data until that new UI is ready. And then once that new data is loaded in the background, then the UI switch instantly and you see everything. ~yeah. ~Use transition without getting too far into the rabbit hole is ~it's ~absolutely nuts. It's Hey, render this in a parallel universe react and then bring it to this one, merge the timelines when that's ready, it's absolutely nuts. And I think it's actually the most powerful hook that a lot of people sleep on, anyway. Without going too deep there. So okay, cool, that sounds really great. So it sounds like your expectations were met. In terms of like initial load performance and server components and nested layouts you had a set of expectations. And [00:14:00] besides the dev server, In terms of what your users would notice, So not developer experience, but user experience, It seems like This was on a good way. Yes. Okay. Where did things start to go wrong? I mean, The blog post is titled The Good, The Bad, The Ugly. The good, clear. Expectations were met. It was doing its job. You had support for nested layout. Let's maybe talk a little bit about the bad. And again, I need to preface this by saying we're not like bashing Next. js. This is not to disparage the work done by the team. Lerob and Tim Newtkins, these are friends and they're good people. ~And ~I think there was a really great post on X the other day where somebody said, look, Next is not bad. Remix is not good. Nothing. It's just, you're effective with what you invest time in. And you could be great with Next and bad with Remix just because you spend more time with Next and that's fine. I think we're very blessed to have so many options in the first place. So again, not disparaging them. But I think it would be naive to admit that we don't sometimes have bad experiences with either, with literally any tool, like you take the world's best hammer and you accidentally smash your thumb. Guess what? You've had a bad experience with a great tool, [00:15:00] right? I think this is not bad. So with that prefacing could we speak a little bit to the bad sides of your experience with AppRouter? Yeah I already mentioned the dev server experience. I think that is like the biggest thing, ~uh,~ that you experience on a daily or like hour by hour basis. As you're using it it just takes a long time to compile everything. And the dev server crashes repeatedly because of a memory leak. And like you expect these things early on. So like ~one, ~one of the things was it was marketed as production ready. You're ~like~ way too early in my opinion. And so like, Oh, production ready. And we're like, okay. But then it's a year later after it was marked production ready. And it's still just now getting there, this was like last fall it was like a year later and it was like, okay, finally, everything is working. ~What is it going to say?~ ~it was last fall where it was one year since it was released and it was still canary.~ ~Yes. They,~ like you expect things to be rough early on. but as long as there's momentum and things are being fixed it's okay. You expect that. But I think probably one of the most frustrating things is there's just been a very little improvement. There has been some [00:16:00] improvement. and my understanding of they've really been focused on performance. We haven't seen a lot of that yet. I think a lot of this hopefully will be fixed with the new turbo mode, like the turbo pack compiler, I believe it is. Um, I think it's around 97, 98 percent complete now. And I'm seeing reports at it is like way faster. So that is like our light at the end of the tunnel that we're just like desperately hoping, we'll solve our problems. We'll see, ~but yeah. Yeah. Yeah.~ than pages, right? Before we could fetch data ahead of time on the server side per route. Now it's per component. I think that's really cool. And --- it also speaks wonders for the composability story as well, because you can just compose independent self contained components that get their own data. It's absolutely cool. However, when we come to the client side, updates that often Require things like refetching and so on. So if you have a list and you click the delete button on a list, you need to refetch and you'd like to ideally avoid a full page reload. So you still need like client side data [00:17:00] fetching. How has your experience been around that using the app router? Yeah, so ~I, ~we've been loading almost all of our initial data in server components. It's very easy to do that because you don't need any sort of API input. Like you can talk directly to your database from the server component. ~We have a, ~we have like an actions layer in between there. ~And ~But ~it's, ~it's essentially straight to the database. And so that, that works good, but for an app like ours, you want the UI to be updating, like we have metrics, logs, deployments. So as soon as you like get push, you want to see that new deployment in your UI. And we've had to add a ~React~ React query in there. Using Blitz to get that and then using polling to get ~that ~live updates. But now ~like ~we actually do need that API endpoint. ~Like ~we're using Blitz RPC for that. But now we're ~like ~duplicating the work. We're ~like ~loading ~the server, ~the data on the server and ~one, ~one approach, and then we're also loading it on the client with a different endpoint. ~And so ~I would really like if server components just had a live feature. Which I recently [00:18:00] saw a tweet by Paiya about something magical around this, that would ~be, that'd ~be really cool. I don't know if this is something Next. js is considering or what. ~Yeah, I think like ~in retrospect, I think maybe we should just be doing ~the server side approach or sorry, ~the client side approach and just using React query for everything. That way you get it for the initial load and then also the live polling comes for free. ~is like~ How we build it with the pages router. There has to be a way to do this from the server side, right? You just don't close the connection and you use server sent events over a long period of time to keep sending like log lines, for example, I think of this would, however, need to be solved at the framework level. And you'd need some type of heuristic, maybe export const configuration persistent true or something like that, but then how do you like push message? Yeah, it's very complicated, but I agree. It would be really cool if next year supported this. And yes, I also agree. The thing that Sunil shared was using party kit with server components and party kit is. Cloudflare dual build objects exposed over web sockets. So you get like real time data from the edge for like multiplayer cases, [00:19:00] which edge means low latency and you can really have great multiplayer, multi cursor experiences. And he has that working with server components. Absolutely nuts. I have not looked into that in depth, but maybe we should get him on the podcast to talk about that. ~I'm sure Emily is making notes of that as we speak.~ ~Um, cool.~ The dev server performance and memory leaks. I assume they. They take a lot of developer time away from y'all. It seems like the work though is done. It seems like you have the console or the dashboard in production, running Next. js 14 using the AppRouter server components. And it's done, as far as I know. ~I think I did log in and go use it. And it,~ we're still in 13 because the upgrade to 14 breaks a lot of things and we have not been able to get that done yet. so there's 14 has there's some sort of major change to the bundling, how things are bundled ~like ~internally. And so this has affected many people where ~you, ~you can't just upgrade to 14. Like stuff doesn't work. There's actually work you have to do to. Figure out how to fix it. We're getting ready to try that again. Hopefully it's easier now. But yes, other than that, yes, the dashboard is basically ~is ~done. And life. Is there a changelog? [00:20:00] And or documentation about getting from 13 to 14. There, yes, there is a change log but the next JS change log is just like a massive wall of like stuff. Oh man. ~so it's. ~Yeah it's not great, but. So there's no migration and just instructions and a big break and change. Wow, that's I do not envy you. I hope this becomes easier. I had no idea. I just went from 13 to 14 in a very small my project is not as comprehensive as yours. Thankfully, I didn't notice. But dang, that's probably another blog post in and of itself. Maybe it could be an open source contribution. From flight control a blog post on here. Here's how to do it. Once you all figure it out So cool in hindsight now that this is done in next GS ~What aspects of I guess this wasn't even a migrations is just like building it from scratch ~What aspects of this would you have approached somewhat differently? You may say oh, I would have just used remix but I'm curious, yeah what would you have considering all the breadth of experiences that you have would you have made different choices? Would you have considered different trade offs? I'd love to hear your take on that. Yeah. So we would definitely use remix and we wish we would have [00:21:00] used remix. I think a few reasons to that. I think remix has a better sort of architecture. It gives the users more control, for example, you as a user own the client and the server entry points. And so you really have full control to do whatever you want there. It's more like AWS in that sense. but Next. js is more like a platform as a service where you only get to do what they allow you to do. and so if you want to do like some observability, like open telemetry stuff, you either, they have a hook for that, but you're very limited to what, you can do with that, or otherwise you have to hack it somehow. And so ~that's one of the things I I also, ~this new server components thing, I feel like it's the complexity has like. Become too much in the framework. Like I get that since, because it's taken so long to fix these like memory leaks and things. and so it's maybe the architecture, maybe how it's built is not as good as it used to be. It's become too complex for its own good. ~the, ~the new compiler and things will get it back on [00:22:00] track. But if we were, going to use server components, I think the things we would do differently is seriously considered just doing the client side fetching for things that we want to be live. So caveat ~there is thumb, ~apparently there is a way to use server components to refresh them revalidate path. And revalidate tag. But then you basically, ~you ~have to add the tag on the server. ~Like ~it's an extra thing you have to do to define a tag. And then on the client, you have to set up ~a, ~an interval to call a server action to invalidate that tag. So I think there might be a way to get the server component refresh. But it's not straightforward ~and ~so ~it's I don't know, ~it feels weird, but that's something you can try if you're on that. I think that's probably the main thing that we would do differently there. That's super reasonable. I share your pain. I've actually implemented real time, not through colon, but through sockets. ~Where I would, it was similar. ~I would get all the initial data on the server side and then I would have to query. The WebSocket on the client side and [00:23:00] at some point stuff changes in between server render and client render. And then you have a really weird scenario. Yeah, I would also, given those constraints, opt for just client side fetching and rendering as well in hindsight. ~Um,~ I love what you said about Remix. I, a lot of people have asked me why I'm going Remix and I think you answered the question better than I could, so I might steal that. Um, one more thing about Remix and server components. You mentioned the complexity has gone too high, and of course at the time of recording now, Remix doesn't have support for server components. I was in a conversation with Kent, as I mentioned yesterday, and he mentioned The story about why Remix doesn't have server components. And it's literally because Michael Jackson and Ryan Florence, the authors tried it and it did not present better UX. And so they said, we're not doing this basically. And that's so cool. I had never heard that before, but just hearing that commitment to UX from a framework perspective. I was like, this is so respectable. You just literally spit in the face of the hype and go no, if there's no measurable UX benefit, I'm not doing it. And now it's [00:24:00] receiving. Traction because Shopify has this massive CMS with like 6, 000 different react components on the same page that need data and The best way to go about this is server components. So Shopify is buying in therefore remix is buying in which that is almost the exact same problem facebook. com has there's just way too many components that need data It does solve that class of problem But a lot of us don't have that class of scale yet. So interesting. And I'm excited to see Remix's answer to this. I hope it's cohesive with the rest of Remix's sort of design philosophy, which is you get all the control and you just use lower level things that you should know anyway. So you learn two things. You learn the fundamentals and you learn Remix in the process. Anyway without digressing too much, what do you hope for? For the future of the AppRouter and, some of the improvements ~we ~I assume ~you, ~you hope for a much faster dev server as do I, as do many of us what else? ~How, if you could,~ if you had a paint brush and you could paint any future for Next. js with the AppRouter, what would you paint? The if we could get [00:25:00] server live server components or even if they're just like pulling that, that would be incredible in a really ~easy way to way~ easy approach their server components are really powerful and they allow you to share like data driven components, even across like apps. So I think they're, ~I think they're ~very fantastic solution. I think the next JS implementation of them. things to be desired. So I'm really curious to see how Remix approaches this. One of the problems here and I think it's one of the reasons that remix has not implemented them yet is that they're still only available in canary react. Like next JS ~is ~as far as I know, ships, a canary version of react with it. And so there's ~like ~limited documentation around this is still pre release essentially and so that's really frustrating. It'd be nice if all of that was more like public from the react team in like unofficial releases and things I think that is The big thing for ~um ~Next. js, like there it's just like stability and performance [00:26:00] better tracking of errors. right now there's a lot of errors that happen that there's no stack trace and you're just like, what the heck? Like it just literally makes no sense. We've wasted so much time to fix things like this. Okay. It was so good. There was literally like, here's what you're doing. You may have forgot to return. JSX and click here for a link to our docs with more info. It was so perfect. And indeed, the Apple has fallen very far from that tree. ~Um, yeah, ~thank you for sharing those things. I think that's cool because it's a constructive way to see how Next. js might improve. And I think we all want that. We want the best for the ecosystem. PodRocket has a number of listeners and all of them developers across varying experience levels. And some I would, I'm pretty convinced are facing similar decisions as you've made. What advice would you give them on choosing sort of a [00:27:00] routing or rendering or even a framework solution based on your experience here? I would recommend either using a traditional SPA, if it's like a dashboard style thing. So this is like Vite plus TAM stack router, or even react router. If you're, if you want to do something that's a bit more established, or use remix. ~So I, so ~another reason that we didn't consider remix so much in the beginning was like, it has been the server side only thing. Like it doesn't have ~static. ~The static component that the Next. js does guess what? With AppRouter, there's nothing static. It's all server side rendered. And so like they're actually now ~they're, ~they have some like partial static stuff but like the default is server side rendering, ~just ~just like with Remix and. That is it's totally fine. Like you get ~the first~ the first load with remix of server side rendered. But then after that, it's all client side transitions. So don't let that be like a blocker for you. That's so interesting. I had no idea. Because even the docs, I thought say, Hey, server [00:28:00] components execute indeed. But, the server is your local computer, and when you, when the server components execute on your local dev server, then the output is static by default. I had no idea it was serverful by default. ~That's, That really put,~ like the server components do not ship JavaScript to the client for that thing, but it's still dynamic rendered on the server. There's still server running. I That was actually my reason also for not going with Remix initially, because I really loved ISR, Incremental Static Regeneration, where I could say, hey Every time someone visits this page, revalidate it for the next person visiting the page. That's so cool. I got around so many rate limits from like CDNs and CMSs, headless CMSs because of that. But to hear that it's not the case anymore, that makes Next. js and Remix equally server dependent, except you get more control with Remix. And Remix seems to have more of a UX focus based on not necessarily adopting server components just because of novelty, but [00:29:00] more not adopting them based on UX testing. Awesome. Yeah, ~my, ~my hot take is that ISR Is overrated ~that so that ~the user experience of ISR from the US perspective is ~a ~really great, but the implementation is, I think ~is ~overcomplicated. ~Like ~all you need is the stale while revalidate cache header. Which you can use with Remix and CDNs like AWS CloudFront support this natively. ~And so ~for example, we have this on ~our website, ~our flight control website is built with app router. But ~like ~I ~could~ literally cannot figure out how to get the static generation to work in app router. Like it was too confusing. ~And ~so I've just added a middleware that adds the stale wire validate caching header on all the pages and all the assets, the images and everything. ~Which ~that's another frustrating thing is the images are not cached by Next. js. In fact, in their middleware, they prevent you from adding special cache headers on images. If you're not hosted on Brazil. ~And ~so it's, we actually have to, we have a patch in the framework to [00:30:00] change a caching header for images. I want to try to make a PR for this at some point if they'll accept it. But I feel like it's intentional. Anyways, yeah. So there's still our validate header is really great. And so you can use that on any framework, any server, anywhere. You don't need a special Next. js ASR to do that. Okay. That's so good. And I laughed a bit because you were getting more and more triggered as you were talking. But, wow, I had no idea about this preventing stale while revalidating on images. Unless you're hosting on, that's absolutely bananas. I would love to see that mentioned in a blog post. And then read it, read the technical details and implementations about that. Um, probably accompanied with a PR. Anyway, ~um, ~Brandon, we're about to wrap up, but I'm curious, ~um, ~Is there something you want to highlight? This is your moment to highlight, plug anything you want, obviously flight control, since that's your baby. But yeah, I'd love to hear things you've been reading, things you've been listening to, consuming that you'd like to shout out for those listening to go enjoy. Oh, the one thing I want to make sure and mention around the next year is is that routing [00:31:00] type safety was a big pain point for us. ~And ~so we implemented a full routing type safety. in user land. And so I have a blog post on this. I'm sure we can link to it in the show notes. And it's literally all the code is very minimal and you can just copy and paste it into your project and get full time safety for all of your Next. js routes. ~And ~it also has runtime validation. So this is for things like query strings and route parameters. So you can assure that, like if either a number or string. And things like that. It works with Zod and TypeScript. So definitely check that out. That's, wait why do I need to copy and paste it? Why can't I npm install it? So there, I think someone did make a NPM installable version. but I'm a huge fan of copying, pasting things that are ~like ~very small, like utilities basically, because then you have full control. You can customize it to your needs. There's no reason it needs to be an NPM library that then you're like stuck to whatever they're beholden to. It's like the past. a platform as a service versus being a black box [00:32:00] versus AWS. If you can tell I'm very big on this thing. We're like, you own it. It's the same reason that I like the approach of Shad CDN where ~you're, ~you just copy and paste the components. And then you can customize it. That's so cool. I guess the only difficulty there is that it's not versioned. You version it. You're responsible for versioning your own thing. But I see that. I see the control. Thanks for clarifying that. You are indeed a guy who does like black boxes, which I think is so cool. We need more of that. Awesome. Listen, Brandon, it's been such a pleasure having you on the podcast and hearing about your experience and your frustrations and the constructive way in which you go about solving them. I really hope you land that PR around images. And I can't wait to hear how this develops applied control on behalf of the rest of the podcast and myself. Thank you so much for coming and sharing your wisdom with us. Thank you for having me and shout out to all the listeners, make sure you're taking care of yourself and your loved ones.