Building an Enterprise-Level React App with TanStack Router, TanStack Query, Zod, Shadcn UI, Vite, Zustand, and Tailwind CSS
When building enterprise-level applications, developers often face the challenge of balancing performance, scalability, and maintainability. In this blog post, we'll walk through building a React app using a powerful stack: TanStack Router, TanStack Query, Zod, Shadcn UI, Vite, Zustand, and Tailwind CSS. Each tool in this stack plays a crucial role in solving enterprise-scale problems, ensuring the app performs well and is easy to maintain.
We'll cover the following topics:
Project Setup with Vite
Routing with TanStack Router (including lazy loading and file-based routing)
Data Fetching with TanStack Query
Data Validation with Zod
UI Components with Shadcn UI
State Management with Zustand
Styling with Tailwind CSS
1. Setting Up the Project with Vite
Vite is a fast build tool that gives us blazing-fast build times and optimized developer experience. Let’s start by setting up the project.
Install Dependencies
First, create a new Vite project and install the required dependencies:
pnpm create vite@latest my-enterprise-app --template react-ts
pnpm install
pnpm install @tanstack/router @tanstack/react-query zod zustand tailwindcss postcss autoprefixer
Next, configure Tailwind CSS by creating the tailwind.config.js file and updating the content paths to reflect your project:
npx tailwindcss init -p
Add this to your tailwind.config.js:
module.exports = {
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
theme: {
extend: {},
},
plugins: [],
};
With this setup, you can now write Tailwind styles in your components:
return (
<div className="p-6 bg-gray-100 text-center">
<h1 className="text-3xl font-bold underline">Hello Vite + Tailwind!</h1>
</div>
);
2. Routing with TanStack Router
TanStack Router is a powerful routing solution that provides flexibility and enables lazy loading (code splitting), which is essential for large enterprise apps. Let’s explore routing with file-based routing and lazy loading.
File-Based Routing Structure
In enterprise applications, organizing routes and their dependencies helps keep the codebase maintainable and scalable. Here’s an ideal structure for routing in a large-scale app:
├── __root.tsx # Root file for the app
├── posts # Folder for the /posts route
│ ├── -components # UI components specific to /posts
│ ├── -api # API communication hooks for /posts
│ ├── -types # Type definitions for /posts
│ ├── -functions # Utility functions for /posts
│ ├── route.lazy.tsx # Lazy route for /posts
│ ├── route.tsx # Critical route for /posts
│ └── $postId # Dynamic sub-route (e.g., /posts/:postId)
│ ├── -components
│ ├── -api
│ ├── -types
│ ├── -functions
│ ├── route.lazy.tsx
│ └── route.tsx
• Critical Route (route.tsx): Essential parts of the route that are loaded during the initial bundle.
• Lazy Route (route.lazy.tsx): Components and UI that are loaded on-demand when the user navigates to the route.
Code Splitting in TanStack Router
Code splitting allows you to break up the JavaScript bundle into smaller chunks that are loaded only when necessary. This improves performance by reducing the amount of code needed for the initial page load.
Benefits of Code Splitting:
• Reduced Initial Load: Only critical code is loaded upfront.
• Targeted Loading: Specific parts of the app are loaded only when needed.
• Granular Caching: Chunks can be cached separately, improving performance.
To implement code splitting in TanStack Router, add the .lazy.tsx suffix to file names and use createLazyFileRoute.
Critical Route (route.tsx)
The critical route contains essential route configurations like path parsing, loaders, and metadata.
import { createRoute } from '@tanstack/router';
import { loader } from './-api/postsLoader';
export const postsRoute = createRoute({
path: '/posts',
meta: {
title: 'Posts',
},
loader, // Load initial data here
});
Lazy Route (route.lazy.tsx)
The lazy route is responsible for loading the UI components only when the route is accessed.
import { lazy } from '@tanstack/router';
const Posts = lazy(() => import('./-components/Posts'));
export const postsLazyRoute = createLazyFileRoute({
component: Posts,
errorComponent: lazy(() => import('./-components/Error')),
pendingComponent: lazy(() => import('./-components/Loading')),
});
With lazy loading, components like the error, loading, and the main UI components are loaded only when needed, improving the initial load time of the app.
3. Data Fetching with TanStack Query
TanStack Query is the go-to tool for efficient data fetching, caching, and synchronization in React apps. It simplifies managing server state by providing hooks for fetching, caching, and updating data.
Here’s how you can use TanStack Query to fetch data for your app.
import { useQuery } from '@tanstack/react-query';
import axios from 'axios';
const fetchPosts = async () => {
const { data } = await axios.get('/api/posts');
return data;
};
const PostList = () => {
const { data, error, isLoading } = useQuery(['posts'], fetchPosts);
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error loading posts</div>;
return (
<ul>
{data.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
};
By using TanStack Query, you ensure that data is cached effectively and automatically updated when it becomes stale, improving both user experience and app performance.
4. Data Validation with Zod
Zod is a TypeScript-first schema declaration library that allows you to validate and parse data safely. It’s perfect for validating form inputs, API responses, and other user data.
Here’s an example of using Zod to validate a form:
import { z } from 'zod';
const postSchema = z.object({
title: z.string().min(3),
content: z.string().min(10),
});
const validatePost = (data: any) => {
try {
postSchema.parse(data);
console.log('Valid!');
} catch (e) {
console.error('Invalid', e.errors);
}
};
Zod integrates seamlessly with TypeScript, providing both runtime validation and type safety.
5. UI Components with Shadcn UI
Shadcn UI provides customizable and aesthetic UI components that fit perfectly into modern React projects. Here’s an example of a simple form using Shadcn UI components:
import { Button, Input } from '@shadcn/ui';
export const LoginForm = () => (
<form className="space-y-4">
<Input label="Username" type="text" required />
<Input label="Password" type="password" required />
<Button type="submit">Login</Button>
</form>
);
Shadcn UI offers a rich set of components that allow for flexibility and customization, making it easier to build cohesive UIs in enterprise apps.
6. State Management with Zustand
Zustand is a small but powerful state management library for React. It provides a simple API for managing global state with minimal boilerplate.
Here’s how to set up a simple store in Zustand:
import create from 'zustand';
interface UserState {
isAuthenticated: boolean;
authenticate: () => void;
}
export const useUserStore = create<UserState>((set) => ({
isAuthenticated: false,
authenticate: () => set({ isAuthenticated: true }),
}));
You can then use this store in your components:
const AuthButton = () => {
const { isAuthenticated, authenticate } = useUserStore();
return (
<button onClick={authenticate}>
{isAuthenticated ? 'Logout' : 'Login'}
</button>
);
};
Zustand is ideal for enterprise apps because of its simplicity, flexibility, and performance.
7. Styling with Tailwind CSS
Tailwind CSS is a utility-first CSS framework that allows you to build responsive and modern UIs quickly.
Here’s an example of a simple dashboard layout styled with Tailwind:
const Dashboard = () => (
<div className="flex min-h-screen">
<aside className="w-64 bg-gray-800 text-white p-4">Sidebar</aside>
<main className="flex-1 p-6 bg-gray-100">Main content</main>
</div>
);
Tailwind’s utility-first approach makes it easy to style components without needing to write custom CSS, ensuring consistency across your app.
Conclusion
Building an enterprise-level React app requires choosing the right tools that scale with the complexity of the project. By combining TanStack Router for routing, TanStack Query for data fetching, Zod for validation, Shadcn UI for UI components, Vite for fast builds, Zustand for state management, and Tailwind CSS for styling, you can create highly performant, maintainable, and scalable apps.
Whether you’re building a CRM, dashboard, or any large-scale app, this stack provides the foundation to handle enterprise needs with ease.