Setting Up a Modern React + TypeScript Project with Vite
Scaffold a new React + TypeScript project using Vite, and understand the purpose of every file and folder it generates, plus the development server and production build process.
Modern React development starts with a build tool that turns your TypeScript/JSX source files into something the browser can run, and gives you fast feedback while you work. Vite (French for 'fast') is the standard modern choice for this, and its official React + TypeScript template gets you a fully working project in under a minute.
Why Vite
Vite is a build tool with two jobs: during development, it serves your source files directly to the browser using native ES modules and only compiles/transforms each file on demand as it's requested, which makes the dev server start almost instantly even on large projects and gives near-instant hot updates when you save a file. Older tools (like Create React App's Webpack setup) had to bundle the entire application before the dev server could start, which got slower as a project grew.
For production, Vite switches strategy and uses Rollup under the hood to bundle and minify your code into a small number of optimized static files — the fast, unbundled dev experience and the small, optimized production build are two different modes of the same tool, chosen automatically depending on whether you run npm run dev or npm run build.
Vite ships official templates for React with TypeScript out of the box, meaning tsconfig.json, TypeScript-aware JSX transforms, and type-checking tooling are already wired up correctly the moment you scaffold a project — you don't hand-configure a bundler to understand .tsx files yourself.
Scaffolding a new project
The official way to start a new React + TypeScript project is the create vite CLI with the react-ts template, run through your package manager. This downloads a minimal starter project, and you then install its dependencies and start the dev server.
After scaffolding, you have a runnable app in four commands: create the project, move into its folder, install dependencies, and start the dev server. From that point, editing any source file and saving triggers an instant update in the browser via Vite's Hot Module Replacement (HMR), without a full page reload or loss of component state where possible.
Anatomy of a generated project
src/ is where your application code lives — every component, hook, and style file you write goes here. Vite watches this folder during development and only re-processes files that actually changed.
public/ holds static assets that should be copied to the output as-is, unprocessed and unhashed — favicons, robots.txt, or files that must be referenced by an exact, stable URL. Anything that should be optimized or bundled (most images, most CSS) instead belongs inside src/ and gets imported into your code so Vite can process it.
src/main.tsx is the actual entry point of the application — the first code that runs. It finds the root DOM element (usually <div id="root"> in index.html), creates a React root there with ReactDOM.createRoot, and renders your top-level <App /> component into it. src/App.tsx is that top-level component — the root of your component tree, which you edit to build out your UI, importing and composing smaller components beneath it.
package.json lists your project's dependencies (React, ReactDOM) and devDependencies (Vite, TypeScript, type definitions, linting tools), plus the scripts section defining commands like dev, build, and preview. tsconfig.json (often split into tsconfig.app.json and tsconfig.node.json in newer templates) configures the TypeScript compiler — target JS version, JSX handling, strictness settings, and which files are included. vite.config.ts configures Vite itself — in a fresh React template this mainly registers the @vitejs/plugin-react plugin, which enables JSX/TSX compilation and Fast Refresh (React's smarter form of HMR that preserves component state across edits).
Development server vs. production build
npm run dev starts Vite's development server, typically at http://localhost:5173. In this mode nothing is bundled up front — files are compiled and served individually as the browser requests them — which is why the server starts almost instantly regardless of project size. This mode also includes helpful error overlays and Fast Refresh, and is never what you ship to users; it includes extra tooling and unminified code.
npm run build produces a production build: Vite uses Rollup to bundle, tree-shake (remove unused code), minify, and content-hash your files, writing the result into a dist/ folder as static HTML/CSS/JS ready to be deployed to any static host or CDN. npm run preview locally serves that dist/ folder so you can sanity-check the actual production output before deploying it — this is different from npm run dev, which never reads from dist/ at all.
Scaffolding and running a Vite + React + TypeScript project
npm create vite@latest runs the latest Vite scaffolding CLI; the extra -- forwards the remaining flags to that CLI rather than to npm itself. --template react-ts selects the React + TypeScript starter specifically (as opposed to plain JavaScript, Vue, Svelte, and other official templates). npm install must run once after scaffolding to download React, ReactDOM, Vite, and TypeScript into node_modules/ before anything will run. npm run dev starts the local dev server with hot reloading; stop it with Ctrl+C when you're done working.
npm create vite@latest my-app -- --template react-ts
cd my-app
npm install
npm run devCode Examples
This file locates the single DOM element the whole app mounts into (#root, defined in index.html), creates a React root there, and renders the top-level <App /> component inside <StrictMode>, which enables extra development-only checks for potential bugs. Nothing else in the app runs before this file does. Expected result: The browser tab loads index.html, index.html loads main.tsx as a module, and the entire React app appears inside the <div id="root"> element.
defineConfig just gives you autocomplete/type-checking for the config object. The react() plugin is what teaches Vite how to compile JSX/TSX syntax and enables Fast Refresh during development — without it, Vite would have no idea what to do with a .tsx file.
// src/main.tsx — the application's real entry point
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App.tsx";
import "./index.css";
createRoot(document.getElementById("root")!).render(
<StrictMode>
<App />
</StrictMode>
);// vite.config.ts — Vite's own configuration file
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
});Generated project structure
The browser loads index.html, which loads main.tsx as a module; main.tsx renders App.tsx into the #root div — everything else in src/ is imported, directly or indirectly, starting from App.
my-app/
├── public/ (static files copied as-is: favicon, etc.)
├── src/
│ ├── main.tsx (entry point: creates the React root, renders <App />)
│ ├── App.tsx (top-level component — root of your UI tree)
│ ├── index.css
│ └── assets/
├── index.html (has <div id="root">, loads /src/main.tsx as a module)
├── package.json (dependencies + scripts: dev, build, preview)
├── tsconfig.json (TypeScript compiler settings)
└── vite.config.ts (Vite + plugin configuration)Important Rules
Use npm create vite@latest <name> -- --template react-ts to scaffold a new React + TypeScript project — this is the modern standard starting point, replacing the now-deprecated Create React App.
Always run npm install before the first npm run dev — a freshly scaffolded project has no node_modules/ yet.
Put processed assets (imported images, styles, code) in src/; put unprocessed, exact-URL static files in public/.
npm run dev is for local development only; npm run build produces the real deployable output in dist/, and npm run preview lets you check that output locally before shipping it.
Where this shows up
Vite with the react-ts template is the default starting point recommended on the official React documentation site for a new client-rendered project, and it's what most modern React tutorials, bootcamps, and production codebases (for small-to-mid-size apps and internal tools) use today. Understanding npm run dev vs npm run build matters the moment you deploy — hosting providers like Vercel, Netlify, and most CI pipelines run npm run build and deploy the resulting dist/ folder, never the dev server.
npm create vite@latest my-app --template react-ts npm create vite@latest my-app -- --template react-ts
Without the extra --, npm tries to interpret --template as its own flag rather than forwarding it to the Vite CLI, and the template selection silently fails or errors — the -- is required to pass flags through to the underlying create-vite script.
[multiple-choice] What is the purpose of the public/ folder in a Vite project? A. It holds your React component source files B. It holds static assets copied to the build output as-is, referenced by a stable, unprocessed URL C. It is where TypeScript configuration lives D. It is only used during production builds, never in development
B. It holds static assets copied to the build output as-is, referenced by a stable, unprocessed URL — Files in public/ are copied to the output directory unchanged and unhashed, useful for assets that need a fixed, predictable URL (like favicon.ico), unlike assets imported from src/, which Vite processes and content-hashes.
[multiple-choice] Which command produces the actual deployable production output? A. npm run dev B. npm install C. npm run build D. npm run preview
C. npm run build — npm run build bundles, tree-shakes, and minifies the app into static files in dist/. npm run dev is for local development only, and npm run preview merely serves the already-built dist/ folder locally to check it.
[true-false] src/main.tsx and src/App.tsx are interchangeable — either can serve as the entry point. A. True B. False
B. False — They play different roles: main.tsx is the actual entry point that creates the React root and calls render; App.tsx is the top-level UI component that main.tsx renders. main.tsx is what index.html loads directly.
Write out, in order, the exact four terminal commands needed to scaffold a brand-new React + TypeScript project named dashboard-app and start its development server.
npm create vite@latest dashboard-app -- --template react-ts cd dashboard-app npm install npm run dev
Scaffold, move into the folder, install, then start the dev server.