Modern React Boilerplate

React is a powerful and flexible library — but that flexibility can be both a blessing and a curse. While it allows developers to build highly performant UIs, the lack of strong opinions often leads to fragmentation and decision fatigue. Starting a new project from scratch means carefully selecting tools that work well together and scale with your needs.
After researching the current ecosystem, I assembled a modern React boilerplate using a thoughtful, balanced tech stack. Here’s a breakdown of each decision, the alternative I considered, and why the chosen solution won out.
Build Tool
A build tool transforms your source code into optimized assets that the browser can run. It handles tasks like bundling JavaScript, compiling TypeScript, processing stylesheets, and enabling hot-reloading during development.
🏆 Vite
Vite offers lightning-fast startup, hot module replacement, and native ES module support. It's optimized for modern frameworks and minimizes configuration overhead.
💤 Webpack
Webpack is still powerful and flexible but requires significantly more setup. It’s slower during development and more complex to configure, especially for modern JavaScript workflows.
Router
A router controls how different components of your app are displayed based on the URL. It enables navigation between views and supports features like nested routes, redirects, and dynamic parameters.
🏆 React Router
React Router is a mature, reliable solution with full support for nested routing, dynamic routes, and lazy loading. It’s well-documented and widely used.
💤 TanStack Router
While innovative, TanStack Router has less documentation and a smaller user base. Its newer API is promising, but not yet as production-hardened or familiar to most teams.
Data Fetching
Data fetching refers to retrieving data from external sources — usually APIs — and integrating it into your application. This process includes loading states, caching, and synchronization with the UI.
🏆 React Query
React Query simplifies data-fetching logic with built-in caching, background syncing, and query invalidation. It excels at managing server state efficiently and declaratively.
💤 SWR
SWR is another solid choice but is best suited for simple use cases. It lacks some advanced features like built-in mutation support, query invalidation, and DevTools that React Query offers.
State Management
State management is how your app keeps track of data that changes over time — like UI settings, form inputs, and user actions—and makes it available across components.
🏆 Zustand
Zustand is a minimal, flexible state manager with a clean API. It avoids boilerplate and works well alongside React hooks.
💤 Redux
Redux remains a robust option for large-scale apps but brings significant complexity and boilerplate. It's better suited for teams already invested in its ecosystem.
Form Validation
Form validation ensures that users enter correct and complete information before submitting a form. It helps verify data types, enforce required fields, and give feedback to users.
🏆 React Hook Form + Zod
React Hook Form offers performant and scalable form state management. Zod brings type-safe, schema-based validation that integrates seamlessly.
💤 Formik + Yup
Formik was once the go-to solution, but it incurs more re-renders and has less efficient performance. Yup is still a good schema validator but lacks some of Zod’s TypeScript integration benefits.
Styling
Styling defines how your app looks — colors, layout, typography, spacing, and responsiveness. The styling approach you choose affects both design flexibility and code maintainability.
🏆 Tailwind CSS
Tailwind’s utility-first approach enables rapid UI development without managing global styles or naming conventions. It results in consistent, maintainable styling within components.
💤 CSS Modules / SCSS
These traditional styling methods require more setup and introduce global style management complexities. While effective, they tend to slow down development compared to Tailwind’s approach.
Authentication
Authentication is the process of verifying a user’s identity and managing their session. It typically involves logging in, storing tokens, and controlling access to protected resources.
🏆 react-oidc-context
This library simplifies OpenID Connect (OIDC) authentication with built-in support for token handling, login/logout, and secure in-memory storage. It integrates cleanly with React’s context model.
💤 Auth0 SDK
Auth0’s SDK is full-featured but tightly coupled to the Auth0 platform, making it less ideal for teams managing their own identity provider or seeking vendor neutrality.
Animation Library
An animation library helps you create transitions and effects like fades, slides, and interactive gestures. These animations enhance user experience by making the UI feel dynamic and responsive.
🏆 Motion
Motion is purpose-built for React, offering declarative animations, gesture support, and physics-based motion. It's beginner-friendly and powerful enough for complex use cases.
💤 GSAP
GSAP is an extremely powerful animation engine, but its imperative model doesn't fit as naturally into React’s declarative paradigm. It also introduces more complexity for simple transitions.
Date Management
Date management libraries help you work with dates and times—formatting, parsing, comparing, and manipulating them accurately and efficiently.
🏆 date-fns
date-fns is a modern, lightweight library with modular utilities for parsing, formatting, and manipulating dates. It works well with modern JavaScript and TypeScript.
💤 Moment.js
Moment.js is now deprecated and known for being heavy and mutating date objects. It’s no longer recommended for new projects.
Testing
Testing involves writing code that verifies your application works as expected. It includes unit tests, integration tests, and UI tests to prevent bugs and ensure reliability.
🏆 Vitest
Vitest is designed specifically for Vite projects. It offers fast test execution, HMR for tests, built-in TypeScript support, and zero-config setup.
💤 Jest
Jest is still widely used and powerful, but its slower performance and heavier configuration make it less ideal for Vite-based projects. Vitest integrates more naturally with the build environment.
Clean Code
Clean code tools automatically format and analyze your code to enforce consistent style and catch potential errors. This ensures a shared standard across the team and improves code quality.
This trio enforces code quality and consistency. ESLint catches common issues, Prettier handles formatting, and Husky runs checks before code is committed.
🏆 Eslint
ESLint is a JavaScript and TypeScript linter that helps enforce consistent code quality and best practices by catching errors, enforcing coding standards, and integrating with modern frameworks. Unlike manual code reviews or relying on editors for syntax errors, ESLint provides automated static analysis to prevent bugs early.
🏆 Prettier
Prettier is an opinionated code formatter that automatically formats code for consistency by enforcing style rules like indentation, line wrapping, and spacing. Unlike manual formatting or relying on team conventions, Prettier eliminates style debates by ensuring all code follows the same structure.
🏆 Husky
Husky is a Git hook manager that helps enforce pre-commit and pre-push checks by running scripts like ESLint, Prettier, or tests before committing code. Unlike relying on manual checks or CI pipelines catching issues later, Husky prevents bad code from being committed in the first place.
Subscribe to my newsletter
Read articles from Namito Yokota directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
