Skip to content

refactor(router-core): add LRU cache in front of parsePathname #4752

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jul 23, 2025

Conversation

Sheraff
Copy link
Contributor

@Sheraff Sheraff commented Jul 22, 2025

We noticed that parsePathname is a performance bottleneck during navigation events. Here's a flamegraph from an application w/ ~300 routes around a navigation event:

Screenshot 2025-07-22 at 19 36 24

This PR proposes a basic least-recently-used cache implementation (that data structure is about 4-5x slower than a Map according to benchmarks, and it uses a little more memory).

We can add caching to parsePathname now that what it returns is readonly (#4705), which should improve the performance of this bottleneck.

The cache is set to a size of 1000. When / if we end up making a pre-built matcher (WIP #4714), we maybe can reduce this size. But parsePathname is still called w/ built pathnames so we probably shouldn't remove the cache entirely.

When benchmarking matchPathname with and without the cache, we notice a ~9x increase in throughput with the cache.

 ✓  @tanstack/router-core  tests/cache.bench.ts > cache.bench 7191ms
     name             hz     min     max    mean     p75     p99    p995    p999     rme  samples
   · original   1,795.61  0.5055  0.7022  0.5569  0.5604  0.6234  0.6464  0.7022  ±0.22%      898
   · cached    16,307.87  0.0562  0.2294  0.0613  0.0608  0.0767  0.1007  0.1152  ±0.17%     8154   fastest

 BENCH  Summary

   @tanstack/router-core  cached - tests/cache.bench.ts > cache.bench
    9.08x faster than original

Assuming this 9x increase translates to a proportional reduction of the self-time seen in the flamegraph, it would go from 55ms to 6ms.

Copy link

nx-cloud bot commented Jul 22, 2025

View your CI Pipeline Execution ↗ for commit 1cbf087

Command Status Duration Result
nx affected --targets=test:eslint,test:unit,tes... ✅ Succeeded 4m 46s View ↗
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 2m 5s View ↗

☁️ Nx Cloud last updated this comment at 2025-07-23 07:31:03 UTC

Copy link

pkg-pr-new bot commented Jul 22, 2025

More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/arktype-adapter@4752

@tanstack/directive-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/directive-functions-plugin@4752

@tanstack/eslint-plugin-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/eslint-plugin-router@4752

@tanstack/history

npm i https://pkg.pr.new/TanStack/router/@tanstack/history@4752

@tanstack/react-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router@4752

@tanstack/react-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-devtools@4752

@tanstack/react-router-with-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-with-query@4752

@tanstack/react-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start@4752

@tanstack/react-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-client@4752

@tanstack/react-start-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-plugin@4752

@tanstack/react-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-server@4752

@tanstack/router-cli

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-cli@4752

@tanstack/router-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-core@4752

@tanstack/router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools@4752

@tanstack/router-devtools-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools-core@4752

@tanstack/router-generator

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-generator@4752

@tanstack/router-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-plugin@4752

@tanstack/router-utils

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-utils@4752

@tanstack/router-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-vite-plugin@4752

@tanstack/server-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/server-functions-plugin@4752

@tanstack/solid-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router@4752

@tanstack/solid-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-devtools@4752

@tanstack/solid-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start@4752

@tanstack/solid-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-client@4752

@tanstack/solid-start-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-plugin@4752

@tanstack/solid-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-server@4752

@tanstack/start-client-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-client-core@4752

@tanstack/start-plugin-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-plugin-core@4752

@tanstack/start-server-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-core@4752

@tanstack/start-server-functions-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-client@4752

@tanstack/start-server-functions-fetcher

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-fetcher@4752

@tanstack/start-server-functions-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-server@4752

@tanstack/start-storage-context

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-storage-context@4752

@tanstack/valibot-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/valibot-adapter@4752

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/TanStack/router/@tanstack/virtual-file-routes@4752

@tanstack/zod-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/zod-adapter@4752

commit: 1cbf087

@Sheraff Sheraff requested a review from schiller-manuel July 22, 2025 17:35
@schiller-manuel
Copy link
Contributor

schiller-manuel commented Jul 22, 2025

does this have any implications when running on dev? e.g. do we need to clear the cache upon hmr?

also we should make the size configurable
size 0 would disable the cache

@Sheraff
Copy link
Contributor Author

Sheraff commented Jul 22, 2025

does this have any implications when running on dev? e.g. do we need to clear the cache upon hmr?

I don't think so. We're parsing strings, using strings as keys. If the string changes, it bypasses the cache. But if it's the same string, it can return the same result, even after a HMR, without any issue.

@Sheraff
Copy link
Contributor Author

Sheraff commented Jul 22, 2025

Serving a local build (not exactly the same performance profile as a staging build in the flamegraph above) I can see the following, around the same nav event:

Without this PR

Screenshot 2025-07-23 at 09 39 18

With this PR

Screenshot 2025-07-23 at 09 39 25

@Sheraff
Copy link
Contributor Author

Sheraff commented Jul 22, 2025

also we should make the size configurable
size 0 would disable the cache

I wasn't sure about this. I can't see anyone playing with this setting unless they have many routes and they actually want to try increasing its size. But for people w/ a small number of routes, I can't imagine why you would disable it. Measuring memory in the browser is kinda annoying but based on vibes I'd imagine this to have a quite minimal memory footprint.

@Sheraff Sheraff force-pushed the router-core-cache-parse-pathname branch from 07ba19a to 6be6968 Compare July 22, 2025 21:40
@Sheraff Sheraff merged commit 182df4d into main Jul 23, 2025
5 checks passed
@Sheraff Sheraff deleted the router-core-cache-parse-pathname branch July 23, 2025 09:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants