Master React Router + Vite + TSX: The 2025 Step-by-Step
Ready to build modern React apps in 2025? This step-by-step guide shows you how to master the powerful trio of React Router, Vite, and TypeScript (TSX).
Daniel Petrova
Senior Frontend Engineer specializing in modern React ecosystems and performant web applications.
The world of frontend development moves at lightning speed. One minute, you’ve mastered a workflow, and the next, a new set of tools promises a faster, more efficient, and more enjoyable developer experience. It can feel like trying to hit a moving target. But every few years, a combination emerges that’s so powerful and cohesive it becomes the new gold standard. For 2025, that standard is unequivocally the trio of Vite, React with TypeScript, and React Router.
If you're tired of slow build times, wrestling with complex Webpack configurations, or chasing down runtime errors that could have been caught during development, you’ve come to the right place. This isn't just another tutorial; it's a step-by-step blueprint for building modern, scalable, and type-safe React applications. We’ll go from an empty folder to a fully routed, multi-page application built on a foundation that’s ready for any feature you can dream up.
Forget the legacy tools and boilerplate fatigue. Let's dive in and build the right way, right from the start.
Why This Stack is the 2025 Standard
Before we write a single line of code, let's understand why this combination is so effective. It’s not just about what's new; it's about how these tools solve real-world problems.
- Vite: The build tool of the future. It offers near-instantaneous server start and Hot Module Replacement (HMR). Unlike traditional bundlers like Webpack, Vite serves code directly to the browser using native ES modules during development, resulting in a ridiculously fast feedback loop.
- TypeScript (TSX): It's JavaScript with superpowers. By adding static types, you catch errors before they ever reach the browser. This leads to more robust code, incredible autocompletion in your editor (IntelliSense), and easier refactoring, especially in large, complex applications.
- React Router (v6+): The definitive routing library for React. The latest versions have been redesigned with a focus on modern React features, introducing powerful data-loading APIs, nested layouts, and a more intuitive hook-based approach.
Here's a quick comparison to illustrate Vite's impact:
Feature | Vite | Create React App (Webpack) |
---|---|---|
Dev Server Start | ~1-2 seconds | ~15-60+ seconds |
Hot Module Replacement (HMR) | Instantaneous | Can be slow, often reloads full page |
Configuration | Minimal, sensible defaults | Abstracted, hard to customize without 'ejecting' |
Prerequisites
To follow along smoothly, you should have:
- Node.js v18 or higher installed on your system.
- A good code editor, like Visual Studio Code.
- A basic understanding of React concepts (components, props, state) and TypeScript syntax (types, interfaces).
Step-by-Step Guide
Let's get our hands dirty. Open your terminal and get ready to build!
Step 1: Scaffolding with Vite + React + TS
Vite's scaffolding tool makes this incredibly simple. Run the following command in your terminal:
npm create vite@latest my-react-router-app -- --template react-ts
This command creates a new directory named my-react-router-app
using the official React and TypeScript template. Now, navigate into the project and install the dependencies:
cd my-react-router-app
npm install
Start the development server to see the magic:
npm run dev
Your terminal will show a local URL (usually http://localhost:5173
). Open it in your browser, and you'll see the default Vite + React starter page. Notice how fast that was!
Step 2: Installing React Router
With our base project running, let's add the routing library. Stop the dev server (Ctrl+C) and run:
npm install react-router-dom
We install react-router-dom
because it contains the specific components and hooks needed for web applications (as opposed to react-router
which is the core library).
Step 3: Setting Up the Modern Router
The modern best practice with React Router v6 is to use a data router like createBrowserRouter
. This unlocks all the new features. Let's configure it.
First, clean up the default App.tsx
file. Replace its content with something simpler for now:
// src/App.tsx
function App() {
return (
My Awesome App
);
}
export default App;
Now, let's set up the router itself. The convention is to do this in your main entry file, src/main.tsx
.
// src/main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import './index.css';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
// 1. Define your routes
const router = createBrowserRouter([
{
path: '/',
element: <App />,
// We will add more routes and an error element soon!
},
]);
// 2. Render the RouterProvider
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<RouterProvider router={router} />
</React.StrictMode>,
);
Notice we're using createBrowserRouter
to define our route configuration and passing it to a <RouterProvider />
component. This replaces the older pattern of wrapping your app in <BrowserRouter>
.
Step 4: Creating Your First Pages & Routes
A single route isn't very useful. Let's create a couple of page components. Create a new folder src/pages
to keep things organized.
src/pages/HomePage.tsx:
export default function HomePage() {
return (
<main>
<h2>Welcome to the Home Page!</h2>
<p>This is the main entry point of our application.</p>
</main>
);
}
src/pages/AboutPage.tsx:
export default function AboutPage() {
return (
<main>
<h2>About Us</h2>
<p>Learn more about what we do!</p>
</main>
);
}
Now, let's update our router in main.tsx
to use these new components.
// src/main.tsx (updated)
// ... imports
import HomePage from './pages/HomePage';
import AboutPage from './pages/AboutPage';
const router = createBrowserRouter([
{
path: '/',
element: <HomePage />,
},
{
path: '/about',
element: <AboutPage />,
},
]);
// ... ReactDOM.render remains the same
If you run npm run dev
now, you can navigate to /
to see the home page and manually change the URL to /about
to see the about page. But we have no way to navigate between them in the UI!
Step 5: Building a Shared Layout and Navigation
Most applications have a shared layout—like a header, navbar, and footer—that persists across pages. React Router makes this elegant with the <Outlet />
component.
Let's create a root layout component. I'll put this in a new src/components
folder.
src/components/RootLayout.tsx:
import { Outlet, Link } from 'react-router-dom';
export default function RootLayout() {
return (
<div className="root-layout">
<header>
<nav>
<h1>React Router 2025</h1>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
</header>
<main>
{/* The <Outlet /> renders the active child route's element */}
<Outlet />
</main>
<footer>
<p>© 2025 - Built with Vite, TSX, and React Router</p>
</footer>
</div>
);
}
Key things to note here:
<Link to="...">
: This is React Router's component for navigation. It's crucial because it prevents a full page reload, providing a smooth, single-page application experience. Always use<Link>
instead of<a href="...">
for internal routing.<Outlet />
: This is a placeholder. React Router will automatically render the correct page component (e.g.,HomePage
orAboutPage
) right where you place the<Outlet />
.
Finally, let's update our router one last time to use this new layout by nesting our routes.
// src/main.tsx (final version)
// ... imports
import RootLayout from './components/RootLayout';
import HomePage from './pages/HomePage';
import AboutPage from './pages/AboutPage';
const router = createBrowserRouter([
{
path: '/',
element: <RootLayout />, // The layout is now the parent route
// Add an errorElement for better error handling
// errorElement: <ErrorPage />,
children: [
{
index: true, // This makes HomePage the default child route for '/'
element: <HomePage />
},
{
path: 'about', // Note: no leading slash
element: <AboutPage />,
},
],
},
]);
// ... ReactDOM.render remains the same
Now, when you run your app, you'll see the header and footer on every page, and you can click the links to navigate seamlessly between Home and About. The content inside <main>
is the only part that changes. This is the power of nested routing!
A Glimpse into Advanced Routing
You now have a solid foundation. But the true power of modern React Router lies in its data-handling capabilities. Here are a few concepts to explore next:
- Dynamic Segments: Create routes for dynamic content like
/posts/:postId
. You can access thepostId
in your component using theuseParams()
hook. - Data Loaders: Define a
loader
function on your route. React Router will call this function and fetch data before your component renders, eliminating loading spinners inside your components and simplifying data management. - Actions: Define an
action
function on your route to handle data mutations (like form submissions). This allows you to co-locate your data reads (loaders) and writes (actions) with your routes.
Conclusion: Your New Foundation
Congratulations! You've successfully built a modern React application from scratch using the best tools available in 2025. You've seen firsthand how Vite provides a superior development experience, how TypeScript ensures code quality, and how React Router enables sophisticated, declarative routing with shared layouts.
This setup isn't just for small projects; it's a scalable, performant, and maintainable foundation that will serve you well for applications of any size. From here, you can confidently explore data loading, authentication flows, and complex UI patterns, knowing your core architecture is solid. Happy coding!