[GH-ISSUE #335] Unexpected next/link Behavior: <Link> with same-origin absolute URL triggers full page reload #78

Closed
opened 2026-05-06 12:37:02 +02:00 by BreizhHardware · 2 comments

Originally created by @sindhukhrisna on GitHub (Mar 7, 2026).
Original GitHub issue: https://github.com/cloudflare/vinext/issues/335

Summary

Using an absolute URL with the same origin in <Link> causes a full page reload instead of client-side navigation.
I'm not sure if this is intended or a missed edge case.

Example:

<Link href="/path">works</Link>
<Link href="https://example.com/path">reloads page</Link>

When the domain matches the current origin, the router should treat it as an internal route and perform client-side navigation.

Expected behavior

Navigation should behave the same for both:

<Link href="/path" />
<Link href="https://example.com/path" />

If the URL origin matches window.location.origin, the router should treat it as an internal navigation and preserve layouts (SPA behavior).

This is how Next.js currently behaves.

Actual behavior

Using an absolute URL with the same domain causes a full page reload, which resets layouts and loses client state.

Steps to reproduce

  1. Create a Vinext app
  2. Add two routes (/ and /path)
  3. Add the following links on /:
<Link href="/path">Relative link</Link>
<Link href="https://example.com/path">Absolute same-origin link</Link>
  1. Click both links

Result:

  • Relative link → client-side navigation
  • Absolute link → full page reload

Environment

  • Vinext: 0.0.24
  • Node: 24.9.0
  • Browser: Chrome

Possible cause

It seems the router only treats URLs starting with / as internal routes. Absolute URLs may not be normalized before routing.

Next.js normalizes same-origin URLs and converts them internally to relative paths before routing.

A similar approach might resolve this behavior.

Workaround

Use relative URLs for internal navigation:

<Link href="/path" />

However, this can be inconvenient or breaks current nextjs codebase when URLs are generated dynamically or include canonical/base URLs.

Originally created by @sindhukhrisna on GitHub (Mar 7, 2026). Original GitHub issue: https://github.com/cloudflare/vinext/issues/335 #### Summary Using an absolute URL with the same origin in `<Link>` causes a full page reload instead of client-side navigation. I'm not sure if this is intended or a missed edge case. Example: ``` <Link href="/path">works</Link> <Link href="https://example.com/path">reloads page</Link> ``` When the domain matches the current origin, the router should treat it as an internal route and perform client-side navigation. #### Expected behavior Navigation should behave the same for both: ``` <Link href="/path" /> <Link href="https://example.com/path" /> ``` If the URL origin matches `window.location.origin`, the router should treat it as an internal navigation and preserve layouts (SPA behavior). This is how Next.js currently behaves. #### Actual behavior Using an absolute URL with the same domain causes a full page reload, which resets layouts and loses client state. #### Steps to reproduce 1. Create a Vinext app 2. Add two routes (`/` and `/path`) 3. Add the following links on `/`: ``` <Link href="/path">Relative link</Link> <Link href="https://example.com/path">Absolute same-origin link</Link> ``` 4. Click both links Result: * Relative link → client-side navigation * Absolute link → full page reload #### Environment * Vinext: 0.0.24 * Node: 24.9.0 * Browser: Chrome #### Possible cause It seems the router only treats URLs starting with `/` as internal routes. Absolute URLs may not be normalized before routing. Next.js normalizes same-origin URLs and converts them internally to relative paths before routing. A similar approach might resolve this behavior. #### Workaround Use relative URLs for internal navigation: ``` <Link href="/path" /> ``` However, this can be inconvenient or breaks current nextjs codebase when URLs are generated dynamically or include canonical/base URLs.
Author
Owner

@Divkix commented on GitHub (Mar 8, 2026):

Fix submitted in #336.

Changes:

  • Added toSameOriginPath() utility that compares new URL(href).origin against window.location.origin and extracts the local path when they match
  • Applied consistently across all four code paths: link.tsx (handleClick + prefetch), navigation.ts (App Router navigateImpl), and router.ts (Pages Router push/replace in both hook and singleton)
  • Added unit tests for the utility and SSR rendering tests for <Link> with absolute URLs
<!-- gh-comment-id:4017736462 --> @Divkix commented on GitHub (Mar 8, 2026): Fix submitted in #336. **Changes:** - Added `toSameOriginPath()` utility that compares `new URL(href).origin` against `window.location.origin` and extracts the local path when they match - Applied consistently across all four code paths: `link.tsx` (handleClick + prefetch), `navigation.ts` (App Router `navigateImpl`), and `router.ts` (Pages Router `push`/`replace` in both hook and singleton) - Added unit tests for the utility and SSR rendering tests for `<Link>` with absolute URLs
Author
Owner

@sindhukhrisna commented on GitHub (Mar 8, 2026):

Thank you for this very fast fix

<!-- gh-comment-id:4018870050 --> @sindhukhrisna commented on GitHub (Mar 8, 2026): Thank you for this very fast fix
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/vinext#78
No description provided.