Skip to content

Astro.routePattern returns lowercased route, dropping camelCase param names #16942

@jacobjiwoo

Description

@jacobjiwoo

Astro Info

Astro                    v6.1.8
Vite                     v7.3.2
Node                     v24.14.0
System                   macOS (arm64)
Package Manager          npm
Output                   server
Adapter                  @astrojs/cloudflare (v13.1.10)
Integrations             @astrojs/react (v5.0.3)

If this issue only occurs in one browser, which browser is a problem?

No response

Describe the Bug

Astro.routePattern returns the route pattern with all characters lowercased, even when the source filename uses camelCase for a dynamic param.

For a file at src/pages/blog/[postId].astro, accessing Astro.routePattern returns /blog/[postid] instead of /blog/[postId].

Interestingly, Astro.params keeps the original casing (Astro.params.postId works as expected). Only the pattern string is affected. RouteData.pathname for fully static routes also preserves casing — so the lowercase normalization is inconsistent within the same RouteData object.

I traced this to packages/astro/src/core/routing/parse-route.ts, in the joinSegments helper:

function joinSegments(segments: RoutePart[][]): string {
  if (segments.length === 0) return '/';
  const arr = segments.map((segment) => {
    return segment.map((part) => (part.dynamic ? `[${part.content}]` : part.content)).join('');
  });
  return `/${arr.join('/')}`.toLowerCase();  // <-- entire path is lowercased
}

The return value is assigned to RouteData.route, and per #11867, Astro.routePattern exposes RouteData.route directly. So this internal normalization leaks all the way to the public API surface.

My guess is the .toLowerCase() was added to make internal route matching case-insensitive, but I couldn't find a code comment or doc explaining the intent — and the existing JSDoc for Astro.routePattern does not mention any normalization. I wanted to confirm with maintainers before proposing a fix, since the right resolution depends on whether this is intentional.

What's the expected result?

Astro.routePattern should preserve the casing used in the original filename. For src/pages/blog/[postId].astro, it should return /blog/[postId].

If the lowercase normalization is intentional for internal matching, I'd suggest either:

  1. Decouple the user-facing pattern from the internal normalized form (keep RouteData.route casing-preserved, lowercase only at the matching step), or
  2. Document the normalization behavior on Astro.routePattern so users aren't surprised.

Happy to open a PR once the intended direction is confirmed.

Link to Minimal Reproducible Example

https://stackblitz.com/edit/github-vsdaaq9e-y6hcp3rn

Participation

  • I am willing to submit a pull request for this issue.

P.S. The https://astro.new/repro link in the bug report template currently fails with a TLS certificate mismatch (Netlify cert is *.netlify.app, missing astro.new SAN). I used a direct StackBlitz import instead.

Metadata

Metadata

Assignees

No one assigned

    Labels

    - P3: minor bugAn edge case that only affects very specific usage (priority)pkg: astroRelated to the core `astro` package (scope)

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions