Capítulo 19 de 57

Chapter 19: Virtual File Routes

Core Idea

Virtual file routes let you build a route tree programmatically in code while still pointing at real route files on disk, giving full control over route organization/URL structure without following (or while partially following) TanStack Router's file-based conventions.

Key Concepts

  • @tanstack/virtual-file-routes package: Provides rootRoute, route, index, layout, and physical functions to declare a virtual route tree that maps to real files.
  • rootRoute(file, children): Declares the virtual root route and its children array.
  • route(path, file, children?): Declares a virtual route at path backed by file; can omit file to just apply a path prefix to nested children; leading/trailing underscores in path are treated literally (use layout for pathless behavior).
  • index(file): Declares a virtual index route backed by file.
  • layout(file, children) / layout(id, file, children): Declares a virtual pathless layout route; an optional explicit id disambiguates it from its filename.
  • physical(urlPath, dir): "Mounts" a real directory that follows standard file-based routing convention under a given URL path; physical('', dir) or physical(dir) merges a directory's routes at the current level with no path prefix.
  • __virtual.ts + defineVirtualSubtreeConfig: Lets you switch a specific subtree of an otherwise file-based-routing project into virtual configuration, via a default export (object, function, or async function returning the subtree config). No rootRoute is needed inside a subtree config.
  • Configuration entry points: Either the virtualRouteConfig option of the tanstackRouter bundler plugin (Vite/Rspack/Webpack), or the virtualRouteConfig key in tsr.config.json for the CLI (as a file path or inline JSON).

Code Examples

// routes.ts
import {
  rootRoute,
  route,
  index,
  layout,
  physical,
} from '@tanstack/virtual-file-routes'

export const routes = rootRoute('root.tsx', [
  index('index.tsx'),
  layout('pathlessLayout.tsx', [
    route('/dashboard', 'app/dashboard.tsx', [
      index('app/dashboard-index.tsx'),
      route('/invoices', 'app/dashboard-invoices.tsx', [
        index('app/invoices-index.tsx'),
        route('$id', 'app/invoice-detail.tsx'),
      ]),
    ]),
    physical('/posts', 'posts'),
  ]),
])
  • What it demonstrates: A virtual route tree combining explicit routes/layouts with a physical() mount that hands off /posts to standard file-based routing convention.

Key Takeaways

  1. Virtual file routes are for customizing route organization/URL mapping while keeping type-safe file-based-routing internals; use physical() to fall back to normal convention for subtrees you don't need to customize.
  2. __virtual.ts allows mixing: most of the app can stay file-based while specific subtrees opt into virtual configuration, and you can nest back and forth arbitrarily deep.
  3. route(path, [children]) without a file argument is a convenient way to apply a shared path prefix to a group of children without introducing an extra component layer.

Connects To

  • Ch 16: Route Trees, lists virtual file routes as one of the tree-configuration styles.
  • Ch 18: File-Based Routing, the convention virtual routes can wrap around or override via physical().
  • Ch 20: Code-Based Routing, a fully manual alternative with no filesystem mapping at all.