Reference · Frontend for backend developers
From nothing to a running, Tailwind-styled app. Two paths. Verified against Vite 8, Tailwind 4, React 19, TanStack Start 1.168 — July 2026.
Prerequisite for both: Node 20.19+ or 22.12+. Check with
node -v. If it is older, install via
nvm rather than replacing your system
Node.
No server. Learning React, internal tools, embedded widgets.
npm create vite@latest my-app \
-- --template react-ts
cd my-app
npm install
npm install tailwindcss @tailwindcss/vite
vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [react(), tailwindcss()],
})
src/index.css — replace all contents
@import "tailwindcss";
npm run dev
Add className="text-3xl text-red-600" to something. Red and large = Tailwind is wired up.
my-app/
├── index.html the real entry point
├── vite.config.ts
├── src/
│ ├── main.tsx mounts React into #root
│ ├── App.tsx
│ ├── index.css @import "tailwindcss"
│ └── components/
└── dist/ npm run build output
Server rendering, routing, server functions. What work uses.
npx create-start-app@latest my-app
# say yes to Tailwind when asked
cd my-app
npm install
Already done if you accepted the prompt. If not, it is identical to Path A step 2 — Start is a Vite app.
npm run dev
Add src/routes/hello.tsx exporting a route, then visit /hello. No registration needed.
my-app/
├── vite.config.ts
├── src/
│ ├── routes/
│ │ ├── __root.tsx <html> shell
│ │ ├── index.tsx /
│ │ └── $id.tsx /:id
│ ├── router.tsx
│ ├── routeTree.gen.ts GENERATED
│ ├── styles.css
│ └── components/
src/routes/hello.tsx
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/hello')({
component: () => <h1>Hello</h1>,
})
| Command | Does | Python analogue |
|---|---|---|
npm install | Install everything in package.json | pip install -r requirements.txt |
npm install X | Add a dependency | pip install X + adding it to the manifest |
npm install -D X | Add a build-time-only dependency | a dev/test extra |
npm run dev | Dev server + HMR | uvicorn --reload |
npm run build | Production output | python -m build |
npm run preview | Serve the build locally — catches build-only bugs | running the built artefact |
npx tsc --noEmit | Typecheck without emitting | mypy . |
| Symptom | Cause | Fix |
|---|---|---|
| Tailwind classes do nothing | The CSS file with @import "tailwindcss" is never imported by your app |
Confirm src/main.tsx imports it (Path A) or __root.tsx does (Path B) |
A tutorial says to run npx tailwindcss init |
It is written for Tailwind v3 | Close it. v4 has no JS config and no PostCSS step. |
| Classes built by string concatenation don't apply | Tailwind scans source text for complete class names; ` text-${color}-500 ` is never a literal in your file |
Write the full class names out in a lookup object or ternary |
| Component renders nothing, no error | Lowercase name — <badge /> is an unknown HTML tag |
Capitalise it |
| State change doesn't re-render | You mutated instead of replacing, so the identity is unchanged | setX([...x, item]), never x.push(item) |
npm run dev works, build fails |
The dev server does not typecheck; the build does | Run npx tsc --noEmit as you go, not at the end |
| Absurd dependency errors after a branch switch | node_modules out of step with the lockfile |
rm -rf node_modules && npm install |
routeTree.gen.ts conflicts in a merge |
It is generated, and two branches generated it differently | Take either side, then let npm run dev rewrite it |