On my last day at Tia I wrote a master vision doc for our TanStack Router app. Here are the parts I can share.
These are battle-tested patterns and lessons learned from using TanStack Router in production since before v1. They worked well for us to iterate quickly, work as a team, and have shockingly few bugs. I can't know how they'll evolve in the future.
TanStack Router 101
If you need a refresher, TanStack Router is the modern React for the rest of us. It combines the best parts of Remix and NextJS for a wonderful type-safe routing experience with all the features you expect:
- type safe routing, you'll get squiggly lines when linking to a path that doesn't exist
- router coordinated data loading, you show 1 loading spinner for everything
- suspense-first design, no more
{isLoading ? ...}
in your UI components - optional file-based routing, your code structure can follow your app structure
- nested routes, your URLs can control specific portions of the UI
UX vision for the app
Our app is based on the principles of multi-page apps. An important nuance makes it different to the multi page apps of yore – we aim to use a unique URL for every significant UI state, but we avoid full-page reloads and round-trips to the server.
This is where TanStack Router shines.
Goals:
- enable multi-tasking
- support easy context sharing
- empower unguided navigation through the app
We're building for power users: they don't need us to hold their hands, they need us to get out of the way. This is the mental image I like to use for what we're building 👇
Guiding principles:
- URL for every significant UI state
- every URL is independent
- cross-page app state is for performance
- a page should always rebuild itself on Cmd+R
- if you share the link with someone, they should see the same thing you did
- reduce clicks
- autofocus first field of forms
- support keyboarding through common tasks
- auto-navigate to next logical place on form submit
- prefer information density
- maintain mental context across operations
Code organization
The app follows a file-based routing setup from TanStack Router.
That means the file structure closely follows the URL structure, which makes things easy to find and fairly easy to collocate.
We try to organize code into vertical modules or components – every page folder should contain everything it needs to work. And every component or function should live at the nearest shared space in the hierarchy.
../../../
imports are the main code smell to look out for.
Horizontal concerns
We've identified a few horizontal concerns like aspects of loading shared data and certain UI atoms that don't belong to any particular page.
We try to treat those like libraries.
There is a shared /data/
and /pages/-components
directory for these which have a path alias for easier imports. This smells a lot like a custom SDK or ORM + component library and should be split off when it matures. Avoid leaking page-specific concerns into these.
Data patterns
TanStack Router supports data loaders at the router level and implements first-party Suspense support.
In practice that means your components don't need to deal with their own loading and error states. You can build your components to focus on the happy path, then let the router handle loading and error states.
A few rules of thumb we’ve developed over time:
- use loaders for data that's required by the whole page
- use suspense queries for data used by a single component
- this lets the router handle coordination but keeps data scoped to your component
- you don't need to handle loading/error states
- use queries for data that depends on interaction
- you have to implement loading/error states
- good for typeaheads and such
- use queries for deferable data used by a single component
- you have to implement loading/error states
- makes app feel faster
- good for supplemental data
- share code between loaders and queries
- it makes life easier when you have a query function that works for both useQuery and loader
- helps you ensure consistent cache keys
- helps ensure consistent data access patterns for trickier things
- yes this starts to look a lot like we're building an SDK or ORM
Go gardening
We like to take a sit-back-and-observe approach. Avoid generalizing code until you've been repeating the same thing and it def looks like a pattern. This makes it easier to keep code flexible and making the abstractions we do build feeling more natural.
Hope this helps. It's a pile of app design guidelines I plan to keep in the next thing I touch.
Cheers,
~Swizec
Continue reading about Tips from 8 months of TanStack/Router in production
Semantically similar articles hand-picked by GPT-4
- TanStack Router – modern React for the rest of us
- 5 apps with the modern web stack
- Using scopes for elegant JAMStack permissions
- How to rewrite your app while growing to a $100,000,000 series B
- Why dataviz does better for your career than TODOapps
Learned something new?
Read more Software Engineering Lessons from Production
I write articles with real insight into the career and skills of a modern software engineer. "Raw and honest from the heart!" as one reader described them. Fueled by lessons learned over 20 years of building production code for side-projects, small businesses, and hyper growth startups. Both successful and not.
Subscribe below 👇
Software Engineering Lessons from Production
Join Swizec's Newsletter and get insightful emails 💌 on mindsets, tactics, and technical skills for your career. Real lessons from building production software. No bullshit.
"Man, love your simple writing! Yours is the only newsletter I open and only blog that I give a fuck to read & scroll till the end. And wow always take away lessons with me. Inspiring! And very relatable. 👌"
Have a burning question that you think I can answer? Hit me up on twitter and I'll do my best.
Who am I and who do I help? I'm Swizec Teller and I turn coders into engineers with "Raw and honest from the heart!" writing. No bullshit. Real insights into the career and skills of a modern software engineer.
Want to become a true senior engineer? Take ownership, have autonomy, and be a force multiplier on your team. The Senior Engineer Mindset ebook can help 👉 swizec.com/senior-mindset. These are the shifts in mindset that unlocked my career.
Curious about Serverless and the modern backend? Check out Serverless Handbook, for frontend engineers 👉 ServerlessHandbook.dev
Want to Stop copy pasting D3 examples and create data visualizations of your own? Learn how to build scalable dataviz React components your whole team can understand with React for Data Visualization
Want to get my best emails on JavaScript, React, Serverless, Fullstack Web, or Indie Hacking? Check out swizec.com/collections
Did someone amazing share this letter with you? Wonderful! You can sign up for my weekly letters for software engineers on their path to greatness, here: swizec.com/blog
Want to brush up on your modern JavaScript syntax? Check out my interactive cheatsheet: es6cheatsheet.com
By the way, just in case no one has told you it yet today: I love and appreciate you for who you are ❤️