Nested Dynamic Routes - Not Navigating

I have reproduced the issue on the latest CLI version.

Yes, I am on the latest version

I have searched existing posts and this report is not a duplicate.

Yes, this isn’t a duplicate

In which of these areas are you experiencing a problem?

App

Expected behavior

Able to navigate to the nested dynamic route

Actual behavior

Nothing happens

Reproduction steps

I’m working on a brand new app using the React Router template. I have a nested dynamic page that I am unable to navigate to. I have no idea why, and it’s driving me insane.

Folder structure inside app/routes:

app._index.tsx

app.purchase-orders.tsx

app.purchase-orders.$id.tsx

app._index.tsx works fine, I can navigate just fine to the Purchase Orders page:

<s-page heading="App Title">
  <s-section heading="Quick Navigation">
    <s-grid gap="base">
      {navigationItems.map((item) => (
        <s-link key={item.url} href={item.url}>
          <s-box padding="base" borderWidth="base" borderRadius="base">
            <s-stack direction="block" gap="small">
              <s-stack direction="inline" gap="small">
                <span style={{ fontSize: "24px" }}>{item.icon}</span>
                <s-heading>{item.title}</s-heading>
              </s-stack>
              <s-text>{item.description}</s-text>
            </s-stack>
          </s-box>
        </s-link>
      ))}
    </s-grid>
  </s-section>
</s-page>

But once I’m on app.purchase-orders.tsx I can’t get to app.purcahse-orders.$id.tsx

<s-stack direction="block" gap="base">
  {purchaseOrders.map((po) => (
    <s-link key={po.id} href={`/app/purchase-orders/${po.id}`}>
      <s-box padding="base" borderWidth="base" borderRadius="base">
        <s-stack direction="block" gap="small">
          <s-stack direction="inline" gap="small">
            <s-heading>
              {po.purchaseOrderNumber || `PO-${po.id.slice(0, 8)}`}
            </s-heading>
            <s-badge
              tone={po.status === "draft" ? "info" : "success"}
            >
              {po.status}
            </s-badge>
          </s-stack>
          <s-text color="subdued">
            {po.vendor || "No vendor"} • Created{" "}
            {new Date(po.createdAt).toLocaleDateString()}
          </s-text>
        </s-stack>
      </s-box>
    </s-link>
  ))}
</s-stack>

I have tried RR’s Link, I’ve tried using s-link, I’ve tried using a click handler with useNavigate to do it programmatically, I can NEVER get to the detail page.

Has anyone run into this problem and have an idea on how to solve it? I’m going slowly insane.

Verbose output

09:25:33 │ React Router │ [shopify-app/INFO] Authenticating admin request | {shop: null}
09:25:33 │ React Router │ [shopify-app/INFO] Authenticating admin request | {shop: null}

Operating system

Mac OS

CLI version

3.86.1

Shell

zsh

Nodejs version

v22.9.0

What language and version are you using in your application?

“engines”: { “node”: “>=20.10” },

If anyone runs into this issue it had to do with React Router’s file based routing.

app._index.tsx

app.purchase-orders.tsx // ←- this had to turn into app.purchase-orders._index.tsx

app.purchase-orders.$id.tsx