How toHandle not found URLs with Remix

If you're creating a Remix application, you may have found that any URL that your app routes doesn't handle will go to the error boundary of the app/root.tsx file.

If you want to create a custom UI for those routes, and maybe access the root loader data to keep things like tracking scripts mounted, you can leverage the route file convention to do it.

First create an app/routes/$.tsx file, this $.tsx in the route file name is the convention for a catch-all route, aka splat route, which is a route that will handle any URL that doesn't match any more specific route.

This means if we have the following files:

  1. app/routes/_.tsx
  2. app/routes/_._index.tsx
  3. app/routes/_.dashboard.tsx
  4. app/routes/_.articles.tsx
  5. app/routes/_.articles_.$id.tsx
  6. app/routes/$.tsx

The first one is a pathless route, / will go to the second route, /dashboard to the third route, /articles will go to the fourth, /articles/123 will go to the fifth, and any other route will go to the sixth route, our splat route.

Here we can now render any UI we want to show a 404, and use a loader to return an actual 404 response.

app/routes/$.tsx
import { json } from "@remix-run/cloudflare"; export async function loader() { return json(null, { status: 404 }) } export default function Component() { return ( <h1>Not Found</h1> ) }

Customize this UI as needed, maybe even return some data from the loader to suggest the user where to go after this.

You can also rename the file to app/routes/_.$.tsx to match inside the app/routes/_.tsx pathless layout so you can re-use the UI from that route too.