Back to All Articles
reactfrontendtypescripttooling

Setting Up Modern React Apps: Frameworks vs Building From Scratch

Learn how to choose the right React setup strategy, skip deprecated tooling, and configure your local development environment correctly.

2026-10-27
Setting Up Modern React Apps: Frameworks vs Building From Scratch

Let's look at how to properly set up a React environment today without falling into legacy tooling traps.

What you'll learn

  • Why you should skip legacy tools like create-react-app
  • How to choose between full-stack frameworks and custom setups
  • Setting up a minimal local development container
  • Bootstrapping your first production-ready component

Why create-react-app Is Dead

If you search older tutorials, you will see npx create-react-app my-app everywhere. Ignore it. That tool is officially deprecated and unmaintained.

Modern React relies heavily on server-side rendering, routing integration, and asset optimization that basic single-page boilerplate templates never handled well. Today, you either adopt a full framework or assemble a custom bundler setup using Vite.

BASH
# Don't do this anymore (deprecated)
npx create-react-app my-app

# Do this instead for a modern Vite + React setup
npx create vite@latest my-react-app -- --template react-ts

Speed Note: Vite starts local dev servers almost instantly because it leverages native ESM in the browser during development instead of bundling your entire node_modules up front.

Choosing Your Architecture: Framework vs Scratch

React is designed for gradual adoption, but your project structure depends entirely on your scale. If you are building a full web application, building from scratch means reinventing routing, code-splitting, and data fetching.

Here is how to make the call:

TSX
// App.tsx - A minimal entry point for a Vite-powered client app
import { useState } from 'react';

export default function App() {
  const [count, setCount] = useState<number>(0);

  return (
    <main className="p-8 max-w-md mx-auto font-sans">
      <h1 className="text-2xl font-bold mb-4">React Local Setup</h1>
      <button 
        onClick={() => setCount(c => c + 1)}
        className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 transition"
      >
        Clicks: {count}
      </button>
    </main>
  );
}

Gotcha: If your app needs SEO or fast initial page loads behind an auth wall, reach for Next.js, Remix, or Expo instead of a plain client-side Vite shell.

Adding React to an Existing Legacy App

Sometimes you don't need a greenfield rewrite. You just need a React widget embedded inside an older server-rendered app (like Rails, Laravel, or a static HTML multi-page site).

Instead of rendering a root for the whole page, target specific DOM nodes:

TSX
// widget-entry.tsx - Mounting React inside a legacy DOM container
import { createRoot } from 'react-dom/client';

function StatusWidget({ status }: { status: string }) {
  return (
    <span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
      System: {status}
    </span>
  );
}

// Find the target container injected by your backend template
const container = document.getElementById('react-status-root');
if (container) {
  const root = createRoot(container);
  root.render(<StatusWidget status="Operational" />);
}

Accessibility Tip: When mounting React into foreign HTML structures, make sure your container elements preserve valid ARIA attributes and don't break existing tab-index flows.

Configuring TypeScript and Strict Mode

Always initialize your React apps with TypeScript enabled from day one. Catching prop mismatches at compile time saves hours of production debugging.

Make sure your main.tsx wraps your root component in StrictMode to catch lifecycle side-effects early during development.

TSX
// main.tsx
import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';
import './index.css';

const rootElement = document.getElementById('root');

if (!rootElement) {
  throw new Error('Failed to find the root element');
}

createRoot(rootElement).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

Summary

Setting up React in modern development comes down to matching your tooling to your deployment target. Skip deprecated boilerplates, use Vite for client apps, and lean on frameworks when you need server-side rendering.

Next Steps

  • Dive into the React Quick Start guide to review core state and props patterns.
  • Explore component composition and custom hooks for scalable logic reuse.