Skip to content

Route generation does not allow plain template literals anymore after 1.166.31 #7216

Description

@kompot

Which project does this relate to?

Router

Describe the bug

Code that worked in router-cli@1.166.30 and below

const routeVarOfferDefinition = `/offers` as const;

const routeApi = getRouteApi(
  `/$locale/_main/(offers)${routeVarOfferDefinition}/$actionId/$tab`,
);

export const Route = createFileRoute(
  `/$locale/_main/(offers)${routeVarOfferDefinition}/$actionId/$tab`,
)({

now in 1.166.31+ throws this error during route generation

Error: Error transforming route file /front/spa/src/routes/$locale/_main/(offers)/-offer/$actionId/$tab.tsx: 
Error: expected route id to be a string literal or plain template literal in /$locale/_main/(offers)/offers/$actionId/$tab

We were relying heavily on semi dynamic URLs (we generate routeVarOfferDefinition like consts during prepare step before TanStack Router kicks in) and actually the error implies that it should work but does not.

I guess this PR is to blame
#7167

Your Example Website or App

https://stackblitz.com/edit/github-t8vtvecd?file=src%2Froutes%2Fabout.tsx,package.json

Steps to Reproduce the Bug or Issue

  1. Go to https://stackblitz.com/edit/github-t8vtvecd?file=src%2Froutes%2Fabout.tsx,package.json
  2. Ctrl + c in terminal
  3. tsr generate -> all good
  4. update version to 1.166.31
  5. npm install
  6. tsr generate fails with expected route id to be a string literal or plain template literal as About page has dynamic part.

Expected behavior

I would expect it to continute working. One of the best Tanstack Router features for our platform as we need to support deep variations for different markets.

Screenshots or Videos

No response

Platform

@tanstack/router-cli@1.166.30

Additional context

No response

Activity

  1. schiller-manuel commented on Apr 17, 2026

    @schiller-manuel
    Collaborator

    This was never supported, if so, it was accidentally.
    This string is managed by router generator, derived from the file path / name.

    the error implies that it should work but does not.
    The error needs refinement. It can be a string but without any placeholders.

    We were relying heavily on semi dynamic URLs (we generate routeVarOfferDefinition like consts during prepare step before TanStack Router kicks in)

    Please provide a more detailed description of your process so we could think of a proper way to support this.

  2. kompot commented on Apr 17, 2026

    @kompot
    Author

    We have several dozens of projects based on single code base. And there's business requirement to make paths customizable. The most notable case is that we have 3 types of projects:

    • 1st needs to mount subproductA at path /subproductA and subproductB at /subproductB
    • 2nd needs to mount subproductA at path /subproductA and subproductB at / because subproductB is the main product on current domain and we'd want URLs to be as nice as possible
    • 3rd need to mount subproductA at path / and subproductB at /subproductB because subproductA is the main product on current domain

    So we had a single configuration file like this

    const bothSubproductAreEqual: boolean = someDynamicCondition();
    const subproductAisMain: boolean = someDynamicCondition();
    const subproductBisMain: boolean = someDynamicCondition();
    
    export const routeVars = {
      subproductA: {
        bare: bothSubproductAreEqual || subproductBisMain ? 'subproductA' : '',
        path: bothSubproductAreEqual || subproductBisMain ? '/subproductA' : '',
        definition: bothSubproductAreEqual || subproductBisMain ? '/subproductA' : '',
      },
      subproductB: {
        bare: bothSubproductAreEqual || subproductAisMain ? 'subproductB' : '',
        path: bothSubproductAreEqual || subproductAisMain ? '/subproductB' : '',
        definition: bothSubproductAreEqual || subproductAisMain ? 'subproductB' : '',
      },
    } as const;

    and then we generated fully static set of vars like this

    export const routeVarSubproductABare = '' as const;
    export const routeVarSubproductAPath = '' as const;
    export const routeVarSubproductADefinition = '' as const;
    export const routeVarSubproductBBare = 'casino' as const;
    export const routeVarSubproductBPath = '/casino' as const;
    export const routeVarSubproductBDefinition = '/casino' as const;

    and then routeVar*Path goes into links and routeVar*Definition goes into routes' definition and also into __virtual.ts route definitions.

    The only downside was that route files were not autoupdated when path was to be changed (like once in a year). Other than that — worked flawlessly. Not sure what was the reason to cut down on that.

    Sure we can do symlinking/copying, we did that with react router before but this leads to all sorts of bugs that far overweigh inability to autoupdate paths (as they are checked by TypeScript anyway during compilation).

  3. codeart1st commented on Apr 27, 2026

    @codeart1st

    For us this change was not a breaker but a surprise and we need to modify our codebase a bit. We have a base ui package which exports the router /constants. And now since only string literals are allowed, we need to drop the usage of our constants. Makes refactoring a little bit more annoying.

  4. schiller-manuel commented on Apr 27, 2026

    @schiller-manuel
    Collaborator

    @kompot i don't understand what you are doing with those subproducts, is it possible to provide a complete example repository that mimics your process?

  5. kompot commented on Apr 27, 2026

    @kompot
    Author

    @schiller-manuel kinda like this, I made an example that would make some sense in terms of real world application (sport popularity between countries)
    https://github.com/kompot/tsr-variable-compile-time-path-segments

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