On this page
A framework migration is a peculiar way to spend time as a solo founder. You can finish a substantial amount of work and leave the customer with exactly the same button.
That can still be worth doing. It needs a better reason than wanting the latest stack.
Bisonflow's 2.0 codebase moves from Next.js to TanStack Start. The app is a workspace where people change filters, inspect issues, edit documents, compare timelines, and move between projects. I wanted its routing and data behavior to be easier to follow while I rebuilt that experience.
Here is why that choice fits Bisonflow. I haven't run a controlled framework benchmark, and I won't dress a preference up as one.

The app was already interactive
Most of the interesting behavior in a project workspace happens after the first page loads. A filter changes. A detail panel opens. Someone edits an issue and expects the surrounding view to agree. The URL should preserve enough state that a reload or a shared link doesn't become a different experience.
TanStack Router gives Bisonflow an explicit route tree, validated search state, loaders, and route-level head configuration. TanStack Start supplies the server side around it. Convex remains the backend. The framework change doesn't make it responsible for a second copy of the project's data.
I like being able to follow those responsibilities in the code. That is a maintainability choice for this application. Next.js can support interactive products too, and moving a small content site for the same reason would be a much weaker argument.
The wider conversation was useful context. TanStack's showcase lists T3 Chat as a Start application, and its Next.js migration guide describes how routing, server calls, metadata, and caching need individual treatment. Another product choosing a framework is a reason to investigate, not evidence that my migration will work.
Route conversion was the visible part
Renaming route files is satisfying because the progress is easy to count. The difficult work sits around them.
A request that arrives directly at a private page needs the same protection as one reached by clicking through the app. A server function needs to validate its own caller. A cache must stop serving old data at the right moment, including when the active account or workspace changes.
In Bisonflow, Clerk owns identity, Convex owns persisted application data, and the client query cache needs to follow that identity. Public pages mount neither the authenticated data providers nor the workspace keyboard layer. Those separations are deliberate. A reader should be able to open an article without starting the private application.
The migration also replaces framework-specific request handlers with Start server routes and server functions. That work includes the parts nobody sees in a launch screenshot: response statuses, redirects, private cache headers, and metadata available in the initial HTML.
Keeping data meant keeping old assumptions visible
A UI rewrite can tempt you to clean up the data model at the same time. Some additions were necessary for the redesigned product, but changing frameworks was not a reason to discard old records.
The migration preserves existing identifiers, file references, and billing records. Historical document snapshots remain available while newer document behavior uses a canonical saved version and editing leases. Compatible changes and bounded migration jobs make the transition reviewable.
Those choices aren't exciting to announce. They matter considerably more than whether a development server feels nicer.
The same applies to money. A new framework, a new visual identity, and a proposed new offer are separate changes. The first two do not authorize repricing anyone's subscription.
SEO needed its own migration
A title that appears after hydration is not the whole search story. Article titles, canonical URLs, social images, missing-page responses, and the sitemap all need deliberate owners.
Start can render public pages on the server and produce route-specific metadata. It doesn't recreate Next.js conventions merely because the old files are still in the repository. Images need prepared sizes. Fonts need delivery rules. Redirects need checking as requests, not only as client navigation.
This was a useful reminder that framework defaults can become undocumented product requirements. Once you remove the framework, those requirements are still yours.
What would make this migration a mistake?
If it made ordinary changes harder to reason about, disrupted access to existing work, or delayed useful product improvements without reducing maintenance cost, I would have paid for novelty.
The reason to keep it is more practical. Routing, server boundaries, and workspace state now fit the way I'm building Bisonflow. The redesign is where users should feel the benefit. The framework should mostly disappear behind it.
Production readiness comes from testing the app's contracts and deployment behavior, not from writing a migration article about them.


