Skip to content

route.tsx and index.tsx conflict when using virtual routing and physical() #5421

Closed

Description

@adharris

Which project does this relate to?

Router

Describe the bug

tldr: When mixing virtual routing and file based routing using the physical virtual route type, the root of the mounted folder cannot have both an index.tsx and a route.tsx. This setup is supported in file-based routing, and is useful for adding layout or context to all child routes.


I'm working on a project with many mostly independent features, each of with has its own set of routes. In my repository, I'd like to have the routes for each feature isolated into the subfolder scoped to to that feature. For example:

/src
├── app/
│   └── routes/  # global routes not related to a feature
└── features
   ├── feature-a
   │     └── routes/  # routes for feature-a
   └── feature-b
         └── routes/  # routes for feature-b

Virtual file routes seem like a great fit for this:

export default rootRoute('app/routes/root.tsx', [
   // ... global routes
    physical('feature-a', 'features/feature-a/routes'),
    physical('feature-b', 'features/feature-b/routes'),
]);

However, when i do this, i can no longer have both a route.tsx and an index.tsx in the feature/*/routes folders. When I do, i get an error like:

Error: Conflicting configuration paths were found for the following routes: "feature", "feature".
Please ensure each Route has a unique full path.
Conflicting files: 
 /home/projects/tanstack-router-xuwk6tn2/src/routes/feature/index.tsx
 /home/projects/tanstack-router-xuwk6tn2/src/routes/feature/route.tsx

This feels broken, when the exact same folder structure works with file based routing.

As a workaround, I can use a pathless route instead of a route.tsx. ie, _layout.tsx and _layout.index.tsx. But this feels like extra verbosity that shouldn't be needed. Adding a shared layout, loader, or context to all children seems like it should be easier.

Your Example Website or App

https://stackblitz.com/edit/tanstack-router-xuwk6tn2?file=src%2Froutes.ts

Steps to Reproduce the Bug or Issue

The attached stackblitz can be swapped between virtual file routes and file based routing by commenting out the virtualRouteConfig option in vite.config.js, and then restarting vite. Vite will automatically scroll the terminal past the router plugin errors, so it will look successful, but if you scroll up yo can see the conflicting path error.

In src/routes.ts, you can swap between mounting the feature folder using physical() and mounting the feature routes directly using route() and feature().

Note that when disabling file based routing, routeTree.gen.ts is identical (ignoring casing) to the generated version when using route()/index(). Also note that when using physical() and getting the error, routeTree.gen.ts is not actually updated, so the app still works (confusing).

Expected behavior

When mounting a directory into a virtual route tree using physical('path', 'folder'), and folder contains both an index.tsx and a route.tsx, the route tree should still generate correctly, with the route.tsx being treated as the parent route for index.tsx, and all other routes in the folder.

Screenshots or Videos

No response

Platform

  • @tanstack/react-router: 1.132.47
  • @tanstack/router-plugin: 1.132.51
  • @tanstack/virtual-file-routes: 1.131.2
  • OS: OSX 15.5 ARM
  • Browser: Chrome
  • Browser Version: 140.0.7339.209 ARM
  • Bundler: Vite
  • Bundler Version: 7.1.7

Additional context

No response

Activity

  1. SeanCassiere commented on Oct 26, 2025

    @SeanCassiere
    Member

    @adharris please attach an example of this with the vitrtual routing config. Using this unit tests can be built out to fix this.

  2. adharris commented on Oct 31, 2025

    @adharris
    Author

    Sorry @SeanCassiere, what are you looking for that's not in the stack blitz?

  3. bhscer commented on Nov 1, 2025

    @bhscer

    I meet the same problem, and what should we provide now?

  4. fmo688428-a11y commented on Jul 8, 2026

    @fmo688428-a11y

    import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
    import {
    Outlet,
    Link,
    createRootRouteWithContext,
    useRouter,
    HeadContent,
    Scripts,
    } from "@tanstack/react-router";
    import { useEffect, type ReactNode } from "react";

    import appCss from "../styles.css?url";
    import { reportLovableError } from "../lib/lovable-error-reporting";

    function NotFoundComponent() {
    return (



    404


    Page not found



    The page you're looking for doesn't exist or has been moved.




    Go home




    );
    }

    function ErrorComponent({ error, reset }: { error: Error; reset: () => void }) {
    console.error(error);
    const router = useRouter();
    useEffect(() => {
    reportLovableError(error, { boundary: "tanstack_root_error_component" });
    }, [error]);

    return (




    This page didn't load



    Something went wrong on our end. You can try refreshing or head back home.



    <button
    onClick={() => {
    router.invalidate();
    reset();
    }}
    className="inline-flex items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90"
    >
    Try again


    Go home




    );
    }

    export const Route = createRootRouteWithContext<{ queryClient: QueryClient }>()({
    head: () => ({
    meta: [
    { charSet: "utf-8" },
    { name: "viewport", content: "width=device-width, initial-scale=1" },
    { title: "فاطمه ❤️ امیر — ۱۱ ماه با هم" },
    { name: "description", content: "یادگاری یازده ماه عاشقانه — از ۱۸ شهریور ۱۴۰۴ تا ۱۸ تیر ۱۴۰۵" },
    { property: "og:title", content: "فاطمه ❤️ امیر — ۱۱ ماه با هم" },
    { property: "og:description", content: "یادگاری یازده ماه عاشقانه — از ۱۸ شهریور ۱۴۰۴ تا ۱۸ تیر ۱۴۰۵" },
    { property: "og:type", content: "website" },
    { name: "twitter:card", content: "summary_large_image" },
    { name: "theme-color", content: "#0a0f2a" },
    { name: "twitter:title", content: "فاطمه ❤️ امیر — ۱۱ ماه با هم" },
    { name: "twitter:description", content: "یادگاری یازده ماه عاشقانه — از ۱۸ شهریور ۱۴۰۴ تا ۱۸ تیر ۱۴۰۵" },
    { property: "og:image", content: "https://pub-bb2e103a32db4e198524a2e9ed8f35b4.r2.dev/97004faf-678b-4033-b625-b794d026b15b/id-preview-8e9c8ef9--70f294e5-7d86-460a-88db-927275e805d2.lovable.app-1783548455916.png" },
    { name: "twitter:image", content: "https://pub-bb2e103a32db4e198524a2e9ed8f35b4.r2.dev/97004faf-678b-4033-b625-b794d026b15b/id-preview-8e9c8ef9--70f294e5-7d86-460a-88db-927275e805d2.lovable.app-1783548455916.png" },
    ],
    links: [
    { rel: "stylesheet", href: appCss },
    { rel: "icon", href: "/favicon.ico", type: "image/x-icon" },
    { rel: "preconnect", href: "https://fonts.googleapis.com" },
    { rel: "preconnect", href: "https://fonts.gstatic.com", crossOrigin: "anonymous" },
    { rel: "stylesheet", href: "https://fonts.googleapis.com/css2?family=Vazirmatn:wght@300;400;500;600;700;800&family=Gulzar&display=swap" },
    ],
    }),
    shellComponent: RootShell,
    component: RootComponent,
    notFoundComponent: NotFoundComponent,
    errorComponent: ErrorComponent,
    });

    function RootShell({ children }: { children: ReactNode }) {
    return (





    {children}



    );
    }

    function RootComponent() {
    const { queryClient } = Route.useRouteContext();

    return (

    {/* Required: nested routes render here. Removing breaks all child routes. */}


    );
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions