Modern React Boilerplate

Namito YokotaNamito Yokota
6 min read

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.

0
Subscribe to my newsletter

Read articles from Namito Yokota directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Namito Yokota
Namito Yokota