Command Palette

Search for a command to run...

Hectal
PHASE 20Advanced ~22 min· topic 7 of 7

Topic 20.7

Frameworks and Build Tools

In one line

A build tool like Vite turns your source into files a browser can run; a framework (Next.js, React Router framework mode, TanStack Start, Expo for mobile) adds routing, data loading, server rendering and deployment conventions; choose a framework when you need those, and plain Vite when a client-only app is enough.

Think of it like this

Building a house. A build tool is the workshop: saws and drills that turn raw wood into finished parts. A framework is a house plan with plumbing and wiring already designed: where the rooms go (routing), how water arrives (data loading), how the house connects to the street (the server). React itself is the bricks. You can build a shed with bricks and a workshop; a family home goes faster with a plan.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

Build tool / bundler
A tool that compiles, joins and optimises your source files into what the browser downloads.
Dev server
A local server for development that compiles on the fly and updates the page when you save.
HMR
Hot module replacement: swapping changed modules into the running page without a full reload.
Framework
A set of tools and conventions on top of React for routing, data loading, rendering and deployment.
SPA
Single-page application: one HTML page where JavaScript handles every navigation in the browser.
Loader
A function attached to a route that loads its data before the route renders.
React Native
React for native mobile apps, rendering native views instead of HTML elements.
Expo
The recommended framework and toolset for building React Native apps.

Step by step

01Start a client-only app with Vite

The lightest setup: static files out, no server code. Add React Router and TanStack Query when you need them.

Terminalwhole filebash
$ npm create vite@latest my-app -- --template react-ts
$ cd my-app && npm install && npm run dev

02Start a full-stack app with a framework

Each framework has an official starter. Check its docs for current prompts; they change often.

Terminalwhole filebash
# Next.js (App Router)
$ npx create-next-app@latest my-app --yes

# React Router framework mode
$ npx create-react-router@latest my-app

# Expo (React Native)
$ npx create-expo-app@latest my-app

03See the same idea in each framework: load data before render

Frameworks differ in syntax, but each lets a route get its data on the server before the page renders.

app/routes/post.tsx (React Router framework mode)whole filetsx
import type { Route } from "./+types/post";

export async function loader({ params }: Route.LoaderArgs) {
  return { post: await db.post.find(params.id) }; // runs on the server
}

export default function Post({ loaderData }: Route.ComponentProps) {
  return <h1>{loaderData.post.title}</h1>;
}

04React Native: same React, different elements

State, props and hooks are identical. The primitives and styling change.

app/index.tsx (Expo)whole filetsx
import { useState } from "react";
import { View, Text, Pressable, StyleSheet } from "react-native";

export default function Home() {
  const [count, setCount] = useState(0);
  return (
    <View style={styles.box}>
      <Text>Tapped {count} times</Text>
      <Pressable onPress={() => setCount(count + 1)}>
        <Text>Tap me</Text>
      </Pressable>
    </View>
  );
}

const styles = StyleSheet.create({ box: { flex: 1, alignItems: "center", justifyContent: "center" } });

05Choose

Ask a few questions in order; the first "yes" usually decides.

Choosediagram
Rendering diagram…

Try it yourself

  1. 1

    Watch the loader run first

    In the router example, also click "Post 2" from the script. Predict the order of the logs. Then add await wait(1000) in the loader and notice the old page stays until the data is ready (the router waits, like a framework navigation).

  2. 2

    Add a page to the build

    Add a third post to the static generator. How many files does the "build" make? What would you need to do to update a title after deploying? (Rebuild, or use ISR.)

Code & diagrams

What a framework adds: data loaded before the route renders New tab

React Router's data router running in the browser (Topic 13.5). In framework mode the same `loader` lives in a route module and runs on the server, and the page is server-rendered with its data.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

loader runs for post 1
screen: Learn React
A tiny static site generator New tab

The core of every static generator (Next.js `generateStaticParams`, React Router `prerender`, Astro): loop over the data and render each page to an HTML file at build time. Real tools also add the CSS, the client JavaScript for hydration and the routing.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

dist/blog/hello-react.html 110 bytes
dist/blog/server-components.html 122 bytes
<!DOCTYPE html><html lang="en"><head><title>Hello React</title></head><body><h1>Hello React</h1></body></html>
React Router framework mode: a route module with a loader and an actiontsx
// app/routes/new-post.tsx
import { Form, redirect } from "react-router";
import type { Route } from "./+types/new-post";

export async function action({ request }: Route.ActionArgs) {
  const user = await requireUser(request);            // authorise on the server
  const form = await request.formData();
  const title = String(form.get("title") ?? "").trim();
  if (title.length < 3) return { error: "Title is too short." }; // validate
  await db.post.create({ data: { title, authorId: user.id } });
  return redirect("/posts");
}

export default function NewPost({ actionData }: Route.ComponentProps) {
  return (
    <Form method="post">
      <input name="title" aria-label="Title" />
      <button>Publish</button>
      {actionData?.error && <p role="alert">{actionData.error}</p>}
    </Form>
  );
}

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Use a web-only library in React Native

In an Expo app, render <div>Hello</div> or import a library that calls document.querySelector.

terminal
$ Expo app
── what you'll see ──
The app shows an error screen: there is no DOM in React Native, so `div` is not a known native component and `document` is undefined.

Myth vs fact

Myth

You must use Next.js to use React.

Fact

React works with any setup. Next.js is one framework; React Router framework mode and TanStack Start are others, and Vite alone is fine for client-only apps.

Myth

A framework always makes the app faster.

Fact

Frameworks make fast patterns easier (SSR, code splitting, early data loading), but a heavy client bundle is slow in any framework. Measure (Phase 16).

Myth

React Native apps are web pages in a wrapper.

Fact

React Native renders real native UI components; it is not a WebView. Only your JavaScript logic runs in a JavaScript engine.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    RSC support is a framework-plus-bundler feature: Next.js ships it today, and React Router and others are adding RSC support. Libraries mark client entry points with "use client" so they work in any RSC framework.

  • ▸

    Framework choice affects hosting: Next.js features like ISR and image optimisation need a server or a platform adapter; a static export (output: "export") or a Vite SPA can go on any CDN, but loses server features.

  • ▸

    Vite's dev server serves native ES modules and pre-bundles dependencies; production builds use Rolldown in recent versions. Frameworks like React Router and TanStack Start build on Vite, so Vite plugins and config knowledge carry over.

  • ▸

    For mobile and web from one codebase, Expo can target the web too (React Native for Web), but web-first apps usually stay on a web framework and share only logic and hooks with the native app.

Remember this

  1. 1

    A build tool (bundler) takes your JSX, TypeScript, CSS and imports and produces optimised files: it compiles JSX, joins modules into bundles, splits code into chunks loaded on demand, minifies, adds content hashes to file names for caching, and runs a dev server with hot module replacement (HMR, updating the page as you save). Vite is the standard choice for React apps without a framework (Topic 0.4 and Phase 23); others include Parcel and Rsbuild. The old Create React App was deprecated in 2025, so don't start new projects with it.

  2. 2

    A framework adds what React leaves out (Topic 0.1): routing with code split per route, data loading that starts before rendering (loaders or server components, avoiding waterfalls), server rendering, streaming and static generation (Topic 20.1), mutations (actions), conventions for errors and loading, and deployment adapters. The React team recommends starting new full apps with a framework, because building these pieces yourself well is hard.

  3. 3

    Next.js (Vercel): the App Router with React Server Components, Server Functions, "use cache" and partial prerendering (Topics 20.4 and 20.5), its own bundler Turbopack, and image, font and metadata helpers. It runs on Node.js servers, serverless platforms or as a static export. Best when you want RSC and a large ecosystem today. React Router framework mode (the successor to Remix): the same router from Phase 13 plus a Vite plugin that adds file or config routes, loader and action functions per route module that run on the server, SSR or SPA mode or prerendering per route, and progressive-enhancement forms. A good fit if you already use React Router or want web-standard Request/Response code.

  4. 4

    TanStack Start: a full-stack framework built on TanStack Router (fully type-safe routes, search params and loaders) and Vite, with SSR, streaming and server functions (createServerFn) that you call like normal functions. It suits teams that want end-to-end TypeScript types and already use TanStack Query (Topic 14.6). Other options exist (Astro for content sites with React "islands", Gatsby and Remix in older codebases, Waku as a minimal RSC framework).

  5. 5

    React Native uses React to build native iOS and Android apps: the same components, props, state and hooks, but no DOM: you render <View>, <Text>, <Image>, <Pressable> instead of div and button, and style with JavaScript objects (a Flexbox subset) instead of CSS files. Expo is the recommended framework for it: npx create-expo-app@latest, file-based routing with Expo Router, ready-made device APIs (camera, location, notifications), and cloud builds. Your React knowledge transfers; web-only libraries (anything touching document) don't.

  6. 6

    When do you need a framework? Choose one when you need SEO or fast first paint for public pages (SSR or SSG), many routes with data loading, server-side code next to your UI (forms, auth, secrets), or RSC. A client-only Vite SPA is enough (and simpler to host on any static server) for apps behind a login where SEO doesn't matter (dashboards, admin tools, internal apps), widgets embedded in other sites, or when another backend already serves your API. You can always add a router (Phase 13) and TanStack Query (Topic 14.6) to a Vite app.

Explain it without notes

01

What is the difference between a build tool and a framework?

02

Compare Next.js, React Router framework mode and TanStack Start.

03

When is a Vite SPA the right choice, and when do you need a framework?

04

How is React Native different from React on the web, and what is Expo?

Practice

01

Pick a stack for: (a) a company's internal admin dashboard, (b) a public recipe site with 10,000 recipes, (c) a habit-tracker phone app. One sentence each.

02

Write a loader-based route (any framework) that loads a user by id and shows their name.

Trade-offs

  • ↔

    A framework saves you from building routing, SSR and data loading yourself, but ties you to its conventions, upgrade pace and hosting needs.

  • ↔

    A plain Vite SPA is the simplest to understand and host, but you assemble routing, data fetching and any server rendering yourself.

Done when you can

  • I can explain what a build tool does and what a framework adds.

  • I can describe Next.js, React Router framework mode, TanStack Start and Expo in a sentence each.

  • I can decide when a client-only Vite app is enough.

  • I know what changes and what stays the same in React Native.