Next.js Discord

Discord Forum

Is there a way to allow not-found pages to exist in nested dirs?

Answered
Multiply posted this in #help-forum
Open in Discord
Currently I can only make not-found work by placing it directly in /app but our system is localiced under /app/[locale] and placing it there, or in any other nested folder for nested layouts to work, triggers the default not found error page.
Answered by Multiply
Wrapping up the original issue:

The fix was to add a catch-all route at the same level or deeper than the defined not-found.tsx page.
The catch-all route should return notFound() and it'll select the nearest not-found.tsx.

The not-found.tsx page is unfortunately not SSR rendered for me when testing the solution, so it's not perfect, but got me further.
View full answer

70 Replies

Plott Hound
unfortuantely not! as far as i know
I guess I'll try to rewrite /not-found to a localized path :mind_blow_astonished:
Plott Hound
i'd love to be able to put it in a top level route group like this:
/app
/app/(my-cool-layout)/not-found.tsx
but it just doesnt work
Alternatively I'll have Fastly cache a localized page, and serve that content when it sees a 404 status code, but next.js isn't happy about that usually.
Yes, me too!
Plott Hound
my solution was to import my layout things into the not-found and make it look like the rest of the site
but its not ideal
Wouldn't that cause rerenders and rehydration anew? 👀
Plott Hound
not the layout file sorry just my UI
i have my auth wrapper in (my-cool-layout) so i have no access to auth in not-found which sucks
I've just split my UI up in parallel routes for caching purposes, so it'll be a pain for 404's to reimplement all that. 😦
Plott Hound
yeah it will. i'd recommend just making a simple 404 design for now and pray something changes in the future :lolsob:
We've been holding off on the pages -> app migration since "stable" announcement, and we are still hitting roadblocks.

I can't even get the old 404 page to work anymore, after having both app and pages side-by-side 😦
Plott Hound
let me get back to you in an hour after i've done some experimenting
I think last resort will be handling it in the CDN if I can't make rewrites work. I assume /not-found won't be going through middlewares?
Plott Hound
is it the fact you need custom 404 pages depending on the routes?
I just need them localized.
Plott Hound
ah i see
/app/[locale]/not-found.tsx
Plott Hound
let me get back to you, i just work up and im sure coffee will help
Or even better /app/[locale]/(default)/not-found.tsx so I can have my layouts added
Plott Hound
I'll try using [...locale] but I worry it might match too much.
Plott Hound
yeah see how you get on. im going to do some testing now.
its not ideal but it should work for localisation at least 🤞
I think my problem is mostly matching on non-existing routes.
But it might go away when I add a catch all route?
Plott Hound
yeah it should
which lib are you using for i18n?
as some of them have baked in support for not-found and localisation
None. We're rolling our own for now, since we want to decrease our overall bundlesize.

We used to have next-i18next rolling, but we're never changing locale directly on the page, so it's major overkill.
I mean, we're still using that for our pages route, but we're actively moving away from it.
So I can confirm, adding a catch-all that does notFound indeed selects the nearest not-found.tsx
app/[locale]/(default)/[...slug]/page.tsx
Selects
app/[locale]/(default)/not-found.tsx
But I probably wouldn't suggest using [...locale] unless I'm missing something.
I don't know if you can have multiple catch all segments, and if yes, how greedy they are.
Plott Hound
no i think that would be bad practice and bad dx
i'll keep looking for solutions
but at least this sort of works for now
I think it makes sense you need to call notFound manually, but the default not-found ideally should look for the best matching not-found.tsx.

It's probably going to be difficult to do, as you can have multiple folders with each their own not-found.tsx
I am noticing something funky though. It seems that the layout is flashing in on 404's, but not any other normal page.
I am unsure if this is a dev-mode thing or not, but the DOM only consists of scripts with __next_f.push for error pages.
It's the same for production builds.
Plott Hound
i just tested it and im getting the same. its a white flash that is very noticable
Especially if main-app-*.js is slow to load on slower connections.
Plott Hound
ok i added a loading.tsx to the root and it handles it
not getting the flash anymore
app/loading.tsx or app/[locale]/(default)/loading.tsx?
Plott Hound
app/loading.tsx i tested it without the catch all so its for root level navigation
i'll try it for the route group
I'm not sure I understand how loading.tsx solves it, but I'm keen to see your folder structure. 😄
I see the same thing, that loading in my catch all solves it.
But that'll cause all my catch-all's to have a loading state, which is undesirable.
I might be able to force static?
Plott Hound
ok say i have this structure:
/about/page.tsx
/not-found.tsx

and i try to navigate from /about to /madeup i get a big white flash while it loads and it looks bad.

if i add
/loading.tsx

and do the same it gracefully shows the loading page and i dont get the white flash
I see the same thing as you, but you still get a flash of content.
Since we're using full page caching in our CDN, having it cache the loading state seems bad.
Iterating a bit on this again, I've tried to use dynamic = 'force-static, and also generateStaticParams, but the not-found.tsx under app/[locale]/(default) is not prerendered, or even mentioned by the build process.
https://github.com/vercel/next.js/issues/62228 I'll tag along in this one, I suppose.
Plott Hound
yeah i've spent an hour digging around and it seems to be a bug
follow the issue and pray i guess
I've been praying for so long already. 🥹
@Multiply I've been praying for so long already. 🥹
Plott Hound
wish i had better news, im in the same boat with various issues
I've tried commenting on the issue, but getting feedback from the vercel team has been tough. They also have a bunch of open issues, so I don't blame them, but it's really frustrating, because we really want to be able to use the app directory.
Wrapping up the original issue:

The fix was to add a catch-all route at the same level or deeper than the defined not-found.tsx page.
The catch-all route should return notFound() and it'll select the nearest not-found.tsx.

The not-found.tsx page is unfortunately not SSR rendered for me when testing the solution, so it's not perfect, but got me further.
Answer
It just occurred to me that when we add loading.tsx the not-found.tsx does not give status code 404, but 200. 🕹️
Plott Hound
404 for non-streamed responses