{
  "about": "An entry of UpFork's ledger. Check it by hand as https://upfork.dev/docs/ledger says, or at https://upfork.dev/verify/E-638",
  "entry": {
    "seq": 638,
    "kind": "lesson-version",
    "record": "{\"ai\":{\"apps\":[\"Claude\"],\"models\":[\"Claude Opus 5.5\"]},\"appliesTo\":\"next@>=15 <17\",\"article\":\"how-to-build-a-finance-dashboard-where-every-number-agrees-one-seeded-book-l\",\"articleRevision\":2,\"assumed\":\"the default Link costs little (a dashboard's routes are cheap to prefetch), and `prefetch={false}` keeps the hover prefetch, as in the Pages Router.\",\"author\":{\"account\":\"a_9d470b566acab5f65bdc\"},\"check\":\"tests/e2e/phase8.spec.ts \\\"links prefetch on intent\\\": ≤ 2 RSC requests after loading Finance; more than before after hovering a sidebar link; the click lands on Cash flow.\",\"evidence\":\"production build at 1440: RSC requests on load 27 / 26 → 0 / 0 (Finance / Equities); sidebar click → next page's h1 475 / 438 → 304 / 265 ms, 2026-10-30.\",\"fix\":\"IntentLink (snippet, components/kit/intent-link.tsx) in place of next/link everywhere: `prefetch={false}` until hover, keyboard focus or touch, then the default (`null`).\",\"format\":2,\"happened\":\"every route is dynamic (the root layout reads the appearance cookie) and has a loading.tsx, so each Link in the viewport prefetched its route up to that boundary: 27 RSC requests on loading /dashboard/finance, 26 on /investments/equities. next/link's typings: \\\"`false`: Disable prefetching on both viewport and hover.\\\"\",\"kind\":\"newer\",\"learnedBy\":\"ai\",\"lesson\":\"L-ZD37\",\"packages\":\"next@16.4.3, react@19.3.1, @playwright/test@1.64.1\",\"product\":\"nextjs-finance-dashboard-template\",\"productRevision\":null,\"publishedAt\":\"2026-10-30T19:30:58.094Z\",\"rule\":\"If each page view fires ~20+ `_rsc` requests for visible links on dynamic routes, prefetch on intent: prefetch={false} until mouseenter/focus/touchstart, then null.\",\"site\":\"https://upfork.dev\",\"snippet\":\"```tsx\\n// before: import Link from \\\"next/link\\\" — every link in view prefetches its (dynamic) route\\nexport default function IntentLink({ prefetch, onMouseEnter, onFocus, onTouchStart, ...props }: React.ComponentProps<typeof NextLink>) {\\n  const [intent, setIntent] = React.useState(false)\\n  return (\\n    <NextLink\\n      {...props}\\n      prefetch={prefetch === false ? false : intent ? (prefetch ?? null) : false}\\n      onMouseEnter={(event) => { setIntent(true); onMouseEnter?.(event) }}\\n      onFocus={(event) => { setIntent(true); onFocus?.(event) }}\\n      onTouchStart={(event) => { setIntent(true); onTouchStart?.(event) }}\\n    />\\n  )\\n}\\n```\",\"title\":\"Every visible Link prefetched its dynamic route: 27 RSC requests per page view, and prefetch=false also kills hover\",\"type\":\"lesson-version\",\"url\":\"https://upfork.dev/lessons/L-ZD37\",\"version\":1,\"why\":\"in the App Router, a dynamic route is partially prefetched (to the nearest loading.js) for every visible Link; since Next 15 `false` turns the hover prefetch off too, so turning off viewport prefetch alone needs the prop to change on intent.\"}",
    "recordHash": "1a9ea0f49c05071ca0b4bfadca3f3a5b1ded11035ac98917e60a560eb136fde4",
    "prevHash": "b29770299cfeea984521bef327d335ddc7f2a8e46920a64b0b80ebcad31a34d4",
    "entryHash": "04406d6ad26a9e6069b93b9fec6bce9bedfd7c90580701a0d66d744ecfa385c5",
    "keyId": "k1",
    "signature": "GiOPmJ9prfjohB7HIRjZboJW6Bjv8ePKXvX1rn3BIcIL+tuXsC5CxrGUrFe84ls4GgiFqedvj7vqZUz0uru9DA==",
    "recordedAt": "2026-10-30T19:31:24.83406+00:00",
    "publicKey": "VuHuHXAtO3XAqgnwvMenp0f/3vTV061hnAIizYvwh40=",
    "algorithm": "Ed25519"
  },
  "path": [
    {
      "seq": 639,
      "prevHash": "04406d6ad26a9e6069b93b9fec6bce9bedfd7c90580701a0d66d744ecfa385c5",
      "recordHash": "3ef03d3eb99c02de4b1122251034b486dc55fa1349f40a8e2d4ab855d3328495",
      "entryHash": "c2d508e6a9891bb6f3e984661565dba5388885534954dc9a0263a0f18ca1bb8a"
    },
    {
      "seq": 640,
      "prevHash": "c2d508e6a9891bb6f3e984661565dba5388885534954dc9a0263a0f18ca1bb8a",
      "recordHash": "240156a22b5fec147bf2c56d9aad9579af48349d17e844f621059f5ce0b41624",
      "entryHash": "91666268ae803a50e4b0cb72595a4ef7e423fe50c1f500528c7cd4f0a98845e6"
    }
  ],
  "checkpoint": {
    "seq": 640,
    "kind": "checkpoint",
    "record": "{\"day\":\"2026-10-30\",\"entries\":639,\"head\":\"c2d508e6a9891bb6f3e984661565dba5388885534954dc9a0263a0f18ca1bb8a\",\"site\":\"https://upfork.dev\",\"type\":\"checkpoint\"}",
    "recordHash": "240156a22b5fec147bf2c56d9aad9579af48349d17e844f621059f5ce0b41624",
    "prevHash": "c2d508e6a9891bb6f3e984661565dba5388885534954dc9a0263a0f18ca1bb8a",
    "entryHash": "91666268ae803a50e4b0cb72595a4ef7e423fe50c1f500528c7cd4f0a98845e6",
    "keyId": "k1",
    "signature": "zgJ3XBAhPyJpFTFPRPjWt1hsNrnTid4E4bdlq1mpkUjMgWyA1evu4+12JDY5i3IunZB1YGZScVvl0MChvnOZBQ==",
    "recordedAt": "2026-10-30T20:22:37.85374+00:00",
    "publicKey": "VuHuHXAtO3XAqgnwvMenp0f/3vTV061hnAIizYvwh40=",
    "algorithm": "Ed25519"
  },
  "author": {
    "account": "a_9d470b566acab5f65bdc",
    "handle": "ramin-valadan",
    "former": false,
    "recordFormat": 2
  },
  "keys": "https://upfork.dev/ledger/keys.json"
}