How to Fix: CatchAll route next-intl: no default component was found

5 min read

Fixing the next-intl Catch-All Route Error: “no default component was found”

If your Next.js App Router app throws “no default component was found” after adding a catch-all route with next-intl, the problem is usually not internationalization itself. The real issue is that the App Router cannot resolve a valid page component for one of the matched route segments, especially when a localized catch-all structure and special files like not-found.tsx or invalid route nesting are involved.

Understanding the Root Cause

In a next-intl setup based on the App Router, routes are often nested under a locale segment such as app/[locale]. When you introduce a catch-all route like […slug] or [[…slug]], Next.js expects that every matched branch resolves to a valid default export page component.

The error appears when Next.js matches a path, enters the route tree, and cannot find the expected page.tsx for that branch. In practice, this usually happens for one of these reasons:

  • The catch-all folder exists, but it does not contain a valid page.tsx with a default export.
  • The route is defined at the wrong level, for example outside app/[locale] when your localized navigation expects it inside that segment.
  • A sibling route, layout.tsx, not-found.tsx, or parallel route setup interferes with route resolution.
  • The path generated by next-intl middleware is rewritten into a route branch that has no renderable page.

With the example App Router project from the reproduction repository, the important detail is that localized route matching can expose gaps in your route tree faster than a non-localized app. Once a request is rewritten to something like /en/some/path, Next.js must find a page under that exact branch.

Step-by-Step Solution

The safest fix is to make sure your localized catch-all route lives inside the locale segment and always resolves to a valid page component.

1. Place the catch-all route under the locale directory

Your structure should look like this:

app/
  [locale]/
    [...slug]/
      page.tsx
    layout.tsx
    page.tsx

If you want the route to also handle the locale root without extra segments, use an optional catch-all instead:

app/
  [locale]/
    [[...slug]]/
      page.tsx
    layout.tsx

2. Export a default page component

Your catch-all page must provide a valid default export:

type Props = {
  params: {
    locale: string;
    slug?: string[];
  };
};

export default function CatchAllPage({params}: Props) {
  return (
    <main>
      <h1>Catch-all route</h1>
      <p>Locale: {params.locale}</p>
      <p>Slug: {params.slug?.join('/') ?? 'root'}</p>
    </main>
  );
}

If this file is missing, named incorrectly, or lacks a default export, Next.js throws the exact error from the issue.

3. Verify your locale middleware configuration

Check that your middleware.ts and routing configuration are aligned with the folder structure:

import createMiddleware from 'next-intl/middleware';

export default createMiddleware({
  locales: ['en', 'de'],
  defaultLocale: 'en'
});

export const config = {
  matcher: ['/((?!api|trpc|_next|_vercel|.*\\..*).*)']
};

If middleware rewrites to a locale-prefixed path, the corresponding route must exist under app/[locale].

4. Add a localized not-found boundary when needed

If unmatched slugs should render a friendly 404 instead of surfacing route confusion, define not-found.tsx at the correct level:

app/
  [locale]/
    not-found.tsx
    [...slug]/
      page.tsx
export default function NotFound() {
  return <h1>Page not found</h1>;
}

This does not replace the need for a valid page.tsx, but it helps ensure unresolved content paths fail cleanly.

5. Use optional catch-all only when the root should also match

A common mistake is using […slug] when your app also expects /en to render through the same branch. That will not work, because […slug] requires at least one segment. In that case, switch to [[…slug]]:

app/[locale]/[[...slug]]/page.tsx

This is often the missing piece when the issue appears only for some URLs but not others.

6. Confirm there is no conflicting route structure

Inspect sibling folders under app/[locale]. Conflicts can happen if you mix:

  • page.tsx at one level
  • […slug] at another
  • parallel routes or route groups with incomplete defaults

For example, if you use parallel routes, each slot may require a default.tsx. That is a different but related source of the same error wording in the App Router.

app/
  [locale]/
    @modal/
      default.tsx
      page.tsx

If your app uses named slots and one is missing its fallback, Next.js may complain that no default component was found.

7. Final working example

app/
  [locale]/
    layout.tsx
    page.tsx
    [[...slug]]/
      page.tsx
    not-found.tsx
type Props = {
  params: {
    locale: string;
    slug?: string[];
  };
};

export default function LocalizedCatchAllPage({params}: Props) {
  const path = params.slug?.join('/') ?? '';

  return (
    <main>
      <h1>Localized route</h1>
      <p>Current locale: {params.locale}</p>
      <p>Current path: {path || 'home'}</p>
    </main>
  );
}

With this setup, locale-prefixed requests rewritten by next-intl always land on a valid route component.

Common Edge Cases

  • Using […slug] instead of [[…slug]]: If the route should also match the locale root, a non-optional catch-all will fail for empty segments.
  • Missing default export: A file can exist but still fail if it only has named exports.
  • Wrong file location: Putting the catch-all route in app/[…slug] while middleware rewrites to app/[locale]/… causes a route tree mismatch.
  • Parallel routes: If you use slots like @modal or @sidebar, missing default.tsx files can trigger similar runtime errors.
  • Broken not-found handling: Throwing notFound() without a proper route boundary can make debugging harder, even if it is not the root cause.
  • Static params mismatch: If you use generateStaticParams and omit locale or slug combinations, behavior can differ between development and production.

FAQ

Why does this happen only after adding next-intl?

next-intl usually introduces a locale segment and middleware rewrite flow. That means URLs are resolved through app/[locale], so any missing page in that localized route tree becomes visible immediately.

Do I need […slug] or [[…slug]]?

Use […slug] when at least one extra path segment is required. Use [[…slug]] when the same route should also match the locale root, such as /en.

What does “no default component was found” actually mean?

In this context, it means the matched App Router branch did not resolve to the component Next.js expected. That may be a missing page.tsx default export, or in more advanced setups, a missing default.tsx for a parallel route slot.

The fix is straightforward once you treat it as a route tree resolution problem, not just an i18n problem: make sure the locale-aware branch always ends in a valid default-renderable component.

Leave a Reply

Your email address will not be published. Required fields are marked *