React Native vs Flutter in 2026: Which Should Your Startup Pick?
React Native and Flutter are both mature. The choice isn't about which is better — it's about your team, your timeline, and what you're building. Here's how to decide.
The App Router has been stable since Next.js 13.4 and is now the default starting point for new projects. After shipping ten client projects on it — ranging from simple marketing sites to multi-locale SaaS dashboards — we have a clear picture of where it delivers and where it creates problems that the Pages Router didn't.
This is not a tutorial. It's an honest account of the decisions, mistakes, and lessons from production use.
The App Router's caching model is the most important thing to understand before writing a line of code. It's also the source of the most confusing bugs we've seen in production.
There are four caching layers:
fetch calls within a single render treefetch responses between requests (stored on the server)The problem isn't that these caches exist. The problem is that they interact in ways that are non-obvious until you're debugging a bug where a user sees stale data after an action they just performed.
What we learned:
tags and use revalidateTag after mutations — this is the correct pattern for most dynamic contentcache: 'no-store' is appropriate for truly dynamic data (personalised content, real-time data), not as a blanket solution to caching confusionunstable_cache is stable enough for production; don't avoid it because of the namingThe App Router's default is server components. Everything is a server component unless you add 'use client'.
The mistake we made early: treating the server/client boundary as an architectural preference rather than a capability boundary.
Components should be server components when:
Components should be client components when:
useState, useEffect, useContext)window, localStorage, IntersectionObserver)The practical rule: push the 'use client' boundary as deep as possible. A page that's 80% static content with one interactive button should be a server component with a single 'use client' button component, not a client component page.
The two performance improvements that showed up consistently across projects:
Streaming. The App Router supports streaming HTML through React's Suspense boundaries. For pages with slow data dependencies, wrapping them in Suspense lets the browser receive the page shell immediately and stream in content as it resolves. On one client project, this reduced time-to-first-meaningful-paint from 2.8s to 0.9s on mobile for a data-heavy analytics page.
Parallel data fetching. In the Pages Router, getServerSideProps serialises data fetching by default. In the App Router, server components at different levels of the tree fetch data simultaneously. A layout that fetches user data and a page that fetches content data run in parallel — the response is ready as soon as the slowest one completes.
What we didn't get: Significant LCP improvements for fully static marketing sites. The Pages Router's static generation is already excellent — the App Router doesn't materially improve a site that was already fast.
The App Router is designed with Vercel in mind. Some features work significantly better on Vercel than on other platforms.
Edge runtime — runs anywhere on Vercel with automatic global distribution. Self-hosted requires manual edge node setup.
Image optimisation — Vercel's next/image CDN is fast and automatic. Self-hosted requires a configured image CDN or the Vercel-specific optimisation won't work.
ISR (Incremental Static Regeneration) — works on Vercel with distributed cache invalidation. Self-hosted ISR requires setting up the On-Demand Revalidation API correctly and ensuring your hosting environment supports it.
What works fine anywhere: Standard server-side rendering, static generation, server components (without edge runtime), all standard API routes.
For most client projects, Vercel is the correct choice. The developer experience is excellent, the deployment pipeline integrates with GitHub natively, and the cost for marketing sites is predictable (€20/month Pro is enough for most use cases). We self-host only when a client has data residency requirements (EU-only), existing infrastructure they want to use, or a cost structure where Vercel's pricing doesn't work at scale.
We're not ideologically committed to the App Router. There are cases where Pages Router is the better choice:
Legacy projects. Migrating a large Pages Router codebase to the App Router is a significant engineering effort with limited business payoff for stable sites. Unless there's a specific App Router feature that the project needs, we don't migrate.
Teams unfamiliar with the App Router. The App Router has a steeper learning curve than the Pages Router. For projects where the client will take over development post-launch, Pages Router reduces handoff risk.
Third-party library compatibility. Most major libraries support the App Router now, but some don't. Always check before starting an App Router project with an unusual library requirement.
Simple sites with no caching requirements. A five-page static site benefits minimally from the App Router's complexity. We'll use it (it's the default), but we treat it as straightforward static site generation, not a distributed caching architecture.
After ten projects, our App Router conventions:
Data fetching lives in server components or route handlers — never in client components unless it's client-side-only data (form state, browser APIs).
Every fetch has an explicit cache policy — either cache: 'no-store' for dynamic data or a revalidation period and a tag for invalidation.
'use client' files export only interactive components — they import server components through composition, never the other way.
Layouts fetch shared data once — user session, navigation data, and global config are fetched in the root layout and passed down, not re-fetched in each page.
Error and loading UI are always defined — error.tsx and loading.tsx at every route segment level. Users never see an unhandled error or a blank screen on a slow connection.
The App Router is a genuine improvement over the Pages Router for applications that benefit from its architecture: streaming, parallel data fetching, fine-grained caching, and shared layouts across routes.
For static marketing sites, the improvement is minimal. The Pages Router works fine and is simpler. The App Router adds complexity that only pays off when you need what it provides.
Choose based on what you're building, not what's new.
Building in Next.js and hitting App Router complexity? Start a conversation — we've been through most of the failure modes and can help you navigate them.
We take on a small number of projects each quarter. Tell us what you're building.
React Native and Flutter are both mature. The choice isn't about which is better — it's about your team, your timeline, and what you're building. Here's how to decide.
Webflow looks cheap at launch. Custom code looks expensive. Three years in, the math reverses. Here's what agencies don't tell you before you sign up.