πŸ—οΈ Frontend Architecture

Comprehensive guide to architecture patterns, from monolithic to micro-frontends, rendering strategies, and state management

πŸ“ Introduction to Frontend Architecture

Frontend architecture defines how you structure, organize, and scale your application. The right architecture depends on your team, complexity, and requirements.

Key Decision Factors

πŸ‘₯ Team Size

How many developers work on the codebase? More developers often need more structure.

πŸ“Š Complexity

Simple landing page vs enterprise dashboard? Complexity drives architecture choices.

πŸ“ˆ Scalability

Will the app grow significantly? Plan for future scale without over-engineering.

πŸš€ Deployment

How often do different parts change? Frequent deploys may need independence.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ FRONTEND ARCHITECTURE SPECTRUM β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ Simple Complex β”‚ β”‚ ────────────────────────────────────────────────────────── β”‚ β”‚ β”‚ β”‚ Static Site β†’ MPA β†’ SPA β†’ Micro-Frontends β†’ Distributed β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ HTML β”‚ β”‚ Server β”‚ β”‚ Client β”‚ β”‚ Multipleβ”‚ β”‚ β”‚ β”‚ Files β”‚ β”‚ Renderedβ”‚ β”‚ Renderedβ”‚ β”‚ Apps β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ Low Team Medium High Multiple β”‚ β”‚ Complexity Complexity Complexity Teams β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

🏒 Monolithic Architecture

A single, unified codebase where all features live together. The simplest and most common starting point.

Structure

// Typical monolithic folder structure
my-app/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ components/       // All components together
β”‚   β”‚   β”œβ”€β”€ Header.jsx
β”‚   β”‚   β”œβ”€β”€ UserCard.jsx
β”‚   β”‚   └── ProductCard.jsx
β”‚   β”œβ”€β”€ pages/            // All pages
β”‚   β”‚   β”œβ”€β”€ Home.jsx
β”‚   β”‚   β”œβ”€β”€ Dashboard.jsx
β”‚   β”‚   └── Settings.jsx
β”‚   β”œβ”€β”€ services/         // API calls
β”‚   β”œβ”€β”€ hooks/            // Custom hooks
β”‚   β”œβ”€β”€ store/            // Global state
β”‚   └── App.jsx           // Single entry point
β”œβ”€β”€ package.json          // One package
└── webpack.config.js     // One build

Characteristics

AspectDescription
Single BuildOne build process, one deployment
Shared DependenciesAll features use same library versions
Unified StateGlobal state management across entire app
Single RoutingOne router handles all navigation
Coupled FeaturesChanges in one area can affect others

Pros & Cons

βœ… PROS
  • Simple setup and debugging
  • No integration overhead
  • Consistent UX
  • Easy refactoring
  • Shared code reuse
❌ CONS
  • Build times grow
  • Hard to scale teams
  • All-or-nothing deploy
  • Technical debt accumulates
  • Large bundle sizes

When to Use

  • Small to medium apps - Up to ~100k lines of code
  • Small teams - 1-5 developers
  • Startups/MVPs - Need to move fast
  • Simple domains - CRUD applications

Code Example

// src/App.jsx - Single entry point with unified routing
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { Provider } from 'react-redux';
import store from './store';

// All pages imported in one place
import Home from './pages/Home';
import Dashboard from './pages/Dashboard';
import Settings from './pages/Settings';

function App() {
    return (
        // Single global store wraps everything
        <Provider store={store}>
            <BrowserRouter>
                <Layout>
                    // All routes defined together
                    <Routes>
                        <Route path="/" element={<Home />} />
                        <Route path="/dashboard" element={<Dashboard />} />
                        <Route path="/settings" element={<Settings />} />
                    </Routes>
                </Layout>
            </BrowserRouter>
        </Provider>
    );
}

🧱 Component-Based Architecture

Building UIs from reusable, self-contained components with clear hierarchies. This is fundamental to modern frontend development.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ COMPONENT HIERARCHY β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ PAGE COMPONENTS β”‚ β”‚ Dashboard, Settings, Profile β”‚ β”‚ ↓ compose ↓ β”‚ β”‚ β”‚ β”‚ CONTAINER COMPONENTS β”‚ β”‚ DashboardContainer, UserContainer β”‚ β”‚ Handles: State, Data Fetching, Business Logic β”‚ β”‚ ↓ pass data to ↓ β”‚ β”‚ β”‚ β”‚ PRESENTATIONAL COMPONENTS β”‚ β”‚ Card, List, Form, Modal β”‚ β”‚ Handles: UI Rendering, Styling, Layout β”‚ β”‚ ↓ compose ↓ β”‚ β”‚ β”‚ β”‚ UI PRIMITIVES β”‚ β”‚ Button, Input, Icon, Text β”‚ β”‚ Handles: Basic UI elements, Design tokens β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Container vs Presentational Pattern

Container Component - Handles Logic

// Container: Manages state, fetching, business logic
function UserListContainer() {
    // State management
    const [users, setUsers] = useState([]);
    const [loading, setLoading] = useState(true);
    const [filter, setFilter] = useState('');
    
    // Data fetching
    useEffect(() => {
        fetchUsers()
            .then(setUsers)
            .finally(() => setLoading(false));
    }, []);
    
    // Business logic - filtering
    const filteredUsers = useMemo(() => 
        users.filter(u => u.name.includes(filter)),
        [users, filter]
    );
    
    // Pass data to presentational component
    return (
        <UserList 
            users={filteredUsers}
            loading={loading}
            filter={filter}
            onFilterChange={setFilter}
        />
    );
}

Presentational Component - Handles UI

// Presentational: Only handles rendering
function UserList({ users, loading, filter, onFilterChange }) {
    // Only UI logic - no business logic!
    if (loading) return <Spinner />;
    
    return (
        <div className="user-list">
            <SearchInput 
                value={filter}
                onChange={onFilterChange}
                placeholder="Search users..."
            />
            
            <div className="user-grid">
                {users.map(user => (
                    <UserCard key={user.id} user={user} />
                ))}
            </div>
            
            {users.length === 0 && (
                <EmptyState message="No users found" />
            )}
        </div>
    );
}

Compound Components Pattern

// Compound components - Flexible composition with shared state

const Tabs = ({ children, defaultValue }) => {
    const [activeTab, setActiveTab] = useState(defaultValue);
    
    return (
        // Shared context for child components
        <TabsContext.Provider value={{ activeTab, setActiveTab }}>
            <div className="tabs">{children}</div>
        </TabsContext.Provider>
    );
};

// Tab trigger button
Tabs.Trigger = function TabTrigger({ value, children }) {
    const { activeTab, setActiveTab } = useContext(TabsContext);
    
    return (
        <button 
            className={activeTab === value ? 'active' : ''}
            onClick={() => setActiveTab(value)}
        >
            {children}
        </button>
    );
};

// Usage - Clean, declarative API
<Tabs defaultValue="general">
    <Tabs.List>
        <Tabs.Trigger value="general">General</Tabs.Trigger>
        <Tabs.Trigger value="security">Security</Tabs.Trigger>
    </Tabs.List>
    
    <Tabs.Content value="general">
        <GeneralSettings />
    </Tabs.Content>
</Tabs>

πŸ”€ Micro-Frontend Architecture

Breaking a frontend into independent, deployable micro-applications. Each team owns and deploys their part independently.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ MICRO-FRONTEND ARCHITECTURE β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ CONTAINER/SHELL β”‚ β”‚ β”‚ β”‚ (Routing, Auth, Layout, Navigation) β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ ↓ ↓ ↓ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ MICRO β”‚ β”‚ MICRO β”‚ β”‚ MICRO β”‚ β”‚ β”‚ β”‚FRONTEND 1β”‚ β”‚FRONTEND 2β”‚ β”‚FRONTEND 3β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ Product β”‚ β”‚ Checkoutβ”‚ β”‚ Account β”‚ β”‚ β”‚ β”‚ Catalog β”‚ β”‚ Flow β”‚ β”‚ Settings β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ React 18 β”‚ β”‚ Vue 3 β”‚ β”‚ React 18 β”‚ β”‚ β”‚ β”‚ Team A β”‚ β”‚ Team B β”‚ β”‚ Team C β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ Each micro-frontend: β”‚ β”‚ β€’ Has its own repository β”‚ β”‚ β€’ Has independent CI/CD pipeline β”‚ β”‚ β€’ Can use different technologies β”‚ β”‚ β€’ Deployed independently β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Integration Approaches

ApproachWhen to UseProsCons
Build-Time NPM packages Simple, Type-safe Can't deploy independently
Server-Side Edge/SSI composition SEO friendly, Fast Complex infrastructure
Run-Time (iFrame) Complete isolation Easy, Secure Limited communication
Run-Time (JS) Module Federation Best DX, Flexible Complex setup

Communication Between Micro-Frontends

// Event Bus Pattern - Loosely coupled communication

class EventBus {
    listeners = new Map();
    
    on(event, callback) {
        if (!this.listeners.has(event)) {
            this.listeners.set(event, new Set());
        }
        this.listeners.get(event).add(callback);
        
        // Return unsubscribe function
        return () => this.listeners.get(event).delete(callback);
    }
    
    emit(event, data) {
        if (this.listeners.has(event)) {
            this.listeners.get(event).forEach(cb => cb(data));
        }
    }
}

// Product Catalog (Team A) - Emits event
function ProductCard({ product }) {
    const addToCart = () => {
        window.__EVENT_BUS__.emit('cart:add', { productId: product.id });
    };
    return <button onClick={addToCart}>Add to Cart</button>;
}

// Checkout (Team B) - Listens for event
function CartIcon() {
    const [count, setCount] = useState(0);
    
    useEffect(() => {
        return window.__EVENT_BUS__.on('cart:add', (item) => {
            setCount(prev => prev + 1);
        });
    }, []);
    
    return <span>πŸ›’ {count}</span>;
}

πŸ“¦ Module Federation

Webpack 5 feature for sharing modules between applications at runtime. The most flexible approach for micro-frontends.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ MODULE FEDERATION β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ HOST APP │◄─────────│ REMOTE APP β”‚ β”‚ β”‚ β”‚ (Shell) β”‚ consumes β”‚ (Products) β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ Loads remote β”‚ β”‚ Exposes: β”‚ β”‚ β”‚ β”‚ modules at β”‚ β”‚ β€’ ProductListβ”‚ β”‚ β”‚ β”‚ runtime β”‚ β”‚ β€’ ProductCardβ”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ ↓ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ SHARED DEPENDENCIES β”‚ β”‚ β”‚ β”‚ react react-dom lodash β”‚ β”‚ β”‚ β”‚ Loaded once, shared between apps β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Configuration

Remote App Configuration

// Remote App webpack.config.js (Products micro-frontend)
const ModuleFederationPlugin = require('webpack').container.ModuleFederationPlugin;

module.exports = {
    output: {
        publicPath: 'http://localhost:3001/',
    },
    plugins: [
        new ModuleFederationPlugin({
            name: 'products',                   // Unique name
            filename: 'remoteEntry.js',         // Entry file
            
            // Modules this app EXPOSES to others
            exposes: {
                './ProductList': './src/components/ProductList',
                './ProductCard': './src/components/ProductCard',
            },
            
            // Dependencies shared with host
            shared: {
                react: { singleton: true },
                'react-dom': { singleton: true },
            },
        }),
    ],
};

Host App Configuration

// Host App webpack.config.js (Shell application)
module.exports = {
    plugins: [
        new ModuleFederationPlugin({
            name: 'shell',
            
            // Remote apps this host CONSUMES
            remotes: {
                products: 'products@http://localhost:3001/remoteEntry.js',
                checkout: 'checkout@http://localhost:3002/remoteEntry.js',
            },
            
            shared: {
                react: { singleton: true },
                'react-dom': { singleton: true },
            },
        }),
    ],
};

Using Remote Modules

// Host App - Dynamic import with React.lazy
const ProductList = React.lazy(() => import('products/ProductList'));

function ProductsPage() {
    return (
        <Suspense fallback={<ProductsSkeleton />}>
            <ProductList />
        </Suspense>
    );
}

🏝️ Islands Architecture

Partial hydration - only interactive parts (islands) are JavaScript, rest is static HTML. Perfect for content-heavy sites.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ ISLANDS ARCHITECTURE β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ Traditional SPA: β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ”‚ β”‚ β”‚ β”‚ ALL JAVASCRIPT β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ Islands Architecture: β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚β–‘β–‘β–‘β–‘β–‘β–‘β–‘β”‚β–ˆβ–ˆβ–ˆβ–ˆβ”‚β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β”‚β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ”‚β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β”‚β–ˆβ–ˆβ–ˆβ–ˆβ”‚β–‘β–‘β–‘β–‘β”‚ β”‚ β”‚ β”‚ STATICβ”‚ JS β”‚ STATIC β”‚ JS β”‚ STATIC β”‚ JS β”‚STATβ”‚ β”‚ β”‚ β”‚ HTML β”‚ β”‚ HTML β”‚ β”‚ HTML β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ ↑ ↑ ↑ β”‚ β”‚ Header Interactive Comments β”‚ β”‚ Island Carousel Island β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Hydration Strategies (Astro)

DirectiveWhen It HydratesUse Case
client:load Immediately on page load Critical interactive elements
client:idle When browser is idle Non-critical interactivity
client:visible When in viewport Below-the-fold content
client:media When media query matches Mobile/desktop only features
client:only Skip SSR, client only Components that can't SSR

Astro Example

// BlogPost.astro - Static by default
---
import Header from '../components/Header.astro';      // Static
import Comments from '../components/Comments.jsx';    // Interactive
import ShareButtons from '../components/ShareButtons.jsx';
---

<Layout>
    <!-- Static header - no JavaScript -->
    <Header />
    
    <!-- Static content -->
    <article>
        <h1>{post.title}</h1>
        <Content />
    </article>
    
    <!-- Interactive Island - hydrate when visible -->
    <ShareButtons client:visible />
    
    <!-- Another island -->
    <Comments postId={post.id} client:visible />
</Layout>
Benefits of Islands:
  • Faster page loads (less JavaScript)
  • Better SEO (static HTML)
  • Progressive enhancement
  • Smaller bundles

🎨 Rendering Patterns

Different strategies for when and where to render your application.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ RENDERING PATTERNS β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ CSR (Client-Side Rendering) β”‚ β”‚ Request β†’ Empty HTML β†’ JS runs β†’ Content β”‚ β”‚ β”‚ β”‚ SSR (Server-Side Rendering) β”‚ β”‚ Request β†’ Server renders β†’ Full HTML β†’ Hydrate β”‚ β”‚ β”‚ β”‚ SSG (Static Site Generation) β”‚ β”‚ Build Time β†’ Pre-rendered β†’ Serve from CDN β†’ Hydrate β”‚ β”‚ β”‚ β”‚ ISR (Incremental Static Regeneration) β”‚ β”‚ Serve Static β†’ Stale? β†’ Rebuild in BG β†’ Update Cache β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Comparison

PatternFirst PaintTTISEODynamic Data
CSR Slow Slow ❌ Poor βœ… Real-time
SSR βœ… Fast Medium βœ… Good βœ… Fresh
SSG βœ… Fastest βœ… Fast βœ… Good ❌ Stale
ISR βœ… Fast βœ… Fast βœ… Good ⚑ Balanced

SSR Example (Next.js)

// pages/products.jsx - Server-Side Rendering
export default function ProductsPage({ products }) {
    // Products already available - server fetched them
    return (
        <div>
            <h1>Products</h1>
            {products.map(product => (
                <ProductCard key={product.id} product={product} />
            ))}
        </div>
    );
}

// Runs on EVERY request on the server
export async function getServerSideProps(context) {
    const res = await fetch('https://api.example.com/products');
    const products = await res.json();
    
    return { props: { products } };
}

ISR Example (Next.js)

// pages/products/[id].jsx - Incremental Static Regeneration
export async function getStaticProps({ params }) {
    const product = await fetchProduct(params.id);
    
    return {
        props: { product },
        
        // Revalidate every 60 seconds
        revalidate: 60
    };
}

export async function getStaticPaths() {
    const topProducts = await fetchTopProducts(100);
    
    return {
        paths: topProducts.map(p => ({ params: { id: p.id } })),
        fallback: 'blocking'  // Generate others on-demand
    };
}

πŸ“Š State Management Patterns

Different approaches to managing application state based on your needs.

Types of State

🏠 Local State

Component-specific state that doesn't need sharing.

useState, useReducer

πŸ”— Shared State

Multiple components need same data.

Context, Redux, Zustand

🌐 Server State

Data from APIs, needs caching/sync.

React Query, SWR

πŸ”— URL State

State reflected in URL for sharing.

useParams, useSearchParams

Pattern Comparison

PatternComplexityBest For
useStateLowComponent UI state
ContextMediumTheme, Auth
Redux/ZustandMedium-HighComplex apps
Jotai/RecoilMediumFine-grained reactivity
React QueryMediumAPI data caching

Redux Toolkit Example

// Modern Redux with Redux Toolkit
import { createSlice, configureStore } from '@reduxjs/toolkit';

const cartSlice = createSlice({
    name: 'cart',
    initialState: { items: [], total: 0 },
    
    reducers: {
        addItem(state, action) {
            const existing = state.items.find(i => i.id === action.payload.id);
            
            if (existing) {
                existing.quantity += 1;
            } else {
                state.items.push({ ...action.payload, quantity: 1 });
            }
            
            state.total = state.items.reduce(
                (sum, item) => sum + item.price * item.quantity, 0
            );
        },
    },
});

// Usage in component
function ProductCard({ product }) {
    const dispatch = useDispatch();
    
    return (
        <button onClick={() => dispatch(addItem(product))}>
            Add to Cart
        </button>
    );
}

React Query Example

// Server state management with React Query
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';

function useProducts(category) {
    return useQuery({
        queryKey: ['products', category],
        queryFn: () => fetchProducts(category),
        staleTime: 5 * 60 * 1000,         // Fresh for 5 minutes
        refetchOnWindowFocus: true,       // Refetch on tab focus
    });
}

// Usage
function ProductsPage() {
    const { data: products, isLoading, error } = useProducts('electronics');
    
    if (isLoading) return <Spinner />;
    if (error) return <Error message={error.message} />;
    
    return products.map(p => <ProductCard key={p.id} product={p} />);
}

πŸ“ Feature-Based Architecture

Organizing code by business feature/domain instead of technical type. Groups related code together.

❌ Traditional (by type)

src/
β”œβ”€β”€ components/
β”œβ”€β”€ hooks/
β”œβ”€β”€ services/
β”œβ”€β”€ store/
└── pages/

// Problem: Related code
// scattered everywhere

βœ… Feature-Based (by domain)

src/
β”œβ”€β”€ features/
β”‚   β”œβ”€β”€ auth/
β”‚   β”œβ”€β”€ products/
β”‚   └── cart/
β”œβ”€β”€ shared/
└── pages/

// Benefit: Related code
// grouped together

Feature Module Structure

src/features/products/
β”œβ”€β”€ components/           // Product-specific components
β”‚   β”œβ”€β”€ ProductList.jsx
β”‚   β”œβ”€β”€ ProductCard.jsx
β”‚   └── ProductFilters.jsx
β”œβ”€β”€ hooks/                // Product-specific hooks
β”‚   β”œβ”€β”€ useProducts.js
β”‚   └── useProductFilters.js
β”œβ”€β”€ services/             // Product API calls
β”‚   └── productService.js
β”œβ”€β”€ store/                // Product state
β”‚   └── productSlice.js
β”œβ”€β”€ types/                // Product types
β”‚   └── product.types.ts
└── index.js              // Public API exports

Public API Pattern

// features/products/index.js - Only export what others need

// Components
export { ProductList } from './components/ProductList';
export { ProductCard } from './components/ProductCard';

// Hooks
export { useProducts } from './hooks/useProducts';

// Types
export type { Product, ProductFilters } from './types/product.types';

// Internal components are NOT exported
// Creates clear boundaries between features


// Usage in pages
import { ProductList, useProducts } from '@/features/products';
import { CartButton } from '@/features/cart';

function ProductsPage() {
    const { products, isLoading } = useProducts();
    
    return (
        <Layout>
            <CartButton />
            <ProductList products={products} loading={isLoading} />
        </Layout>
    );
}

🧹 Clean Architecture

Separating business logic from UI and infrastructure concerns. Dependencies point inward only.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ CLEAN ARCHITECTURE β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ UI LAYER β”‚ β”‚ β”‚ β”‚ (React Components, Hooks) β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ ↓ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ APPLICATION LAYER β”‚ β”‚ β”‚ β”‚ (Use Cases / Services) β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ ↓ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ DOMAIN LAYER β”‚ β”‚ β”‚ β”‚ (Entities, Business Rules, Interfaces) β”‚ β”‚ β”‚ β”‚ Pure business logic, NO dependencies β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ ↑ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ INFRASTRUCTURE LAYER β”‚ β”‚ β”‚ β”‚ (API clients, Storage, External) β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ Dependency Rule: Dependencies point INWARD only β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Layer Responsibilities

LayerContainsDepends On
UIReact components, hooksApplication
ApplicationUse cases, DTOsDomain
DomainEntities, business rulesNothing!
InfrastructureAPI clients, storageDomain (interfaces)

Example

// DOMAIN LAYER - Pure business logic
export class Product {
    constructor(
        public readonly id: string,
        public readonly name: string,
        public readonly price: number,
        public readonly stock: number
    ) {}
    
    // Business rule
    canOrder(quantity: number): boolean {
        return this.stock >= quantity;
    }
}

// APPLICATION LAYER - Use cases
export class GetProductsUseCase {
    constructor(private productRepository: IProductRepository) {}
    
    async execute(filters?: ProductFilters): Promise<ProductDTO[]> {
        const products = await this.productRepository.getAll();
        return products.map(p => ({ id: p.id, name: p.name }));
    }
}

// UI LAYER - React hook
export function useProducts() {
    const [products, setProducts] = useState([]);
    
    const useCase = useMemo(() => {
        const repository = new ProductApiRepository();
        return new GetProductsUseCase(repository);
    }, []);
    
    useEffect(() => {
        useCase.execute().then(setProducts);
    }, []);
    
    return { products };
}

βš›οΈ Atomic Design

Building UI from smallest atoms to complete pages. Creates a systematic component hierarchy.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ ATOMIC DESIGN β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ PAGES Complete page layouts β”‚ β”‚ ──────── HomePage, ProductsPage, CheckoutPage β”‚ β”‚ β–² β”‚ β”‚ β”‚ β”‚ TEMPLATES Page structure without data β”‚ β”‚ ───────── HeaderFooterLayout, TwoColumnLayout β”‚ β”‚ β–² β”‚ β”‚ β”‚ β”‚ ORGANISMS Complex UI sections β”‚ β”‚ ───────── NavigationBar, ProductGrid, CheckoutForm β”‚ β”‚ β–² β”‚ β”‚ β”‚ β”‚ MOLECULES Simple component groups β”‚ β”‚ ───────── SearchBar, ProductCard, FormField β”‚ β”‚ β–² β”‚ β”‚ β”‚ β”‚ ATOMS Basic building blocks β”‚ β”‚ ───── Button, Input, Icon, Label, Avatar β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Component Hierarchy

LevelDescriptionExamples
Atoms Basic building blocks, cannot be broken down further Button, Input, Icon, Label
Molecules Combinations of atoms, simple groups SearchBar, FormField, UserCard
Organisms Complex sections composed of molecules/atoms Header, ProductGrid, Footer
Templates Page structure without real data MainLayout, DashboardLayout
Pages Complete pages with real content HomePage, ProductsPage

Example

// ATOMS - Basic building blocks
function Button({ variant = 'primary', children, ...props }) {
    return <button className={`btn btn-${variant}`} {...props}>{children}</button>;
}

// MOLECULES - Combinations of atoms
function SearchBar({ value, onChange, onSearch }) {
    return (
        <div className="search-bar">
            <Icon name="search" />
            <Input value={value} onChange={onChange} />
            <Button onClick={onSearch}>Search</Button>
        </div>
    );
}

// ORGANISMS - Complex sections
function Header({ user, onSearch }) {
    return (
        <header className="header">
            <Logo />
            <Navigation />
            <SearchBar onSearch={onSearch} />
            <UserMenu user={user} />
        </header>
    );
}

// TEMPLATES - Page structure
function MainLayout({ children, user }) {
    return (
        <div className="main-layout">
            <Header user={user} />
            <main>{children}</main>
            <Footer />
        </div>
    );
}

// PAGES - Complete pages
function ProductsPage() {
    const { user } = useAuth();
    const { products } = useProducts();
    
    return (
        <MainLayout user={user}>
            <h1>Products</h1>
            <ProductGrid products={products} />
        </MainLayout>
    );
}

πŸ“‹ Summary & Decision Guide

Quick Reference

ArchitectureBest ForKey BenefitMain Drawback
MonolithicSmall teams/appsSimplicityScaling issues
Component-BasedUI organizationReusabilityNone (always use)
Feature-BasedMedium teamsClear ownershipRequires discipline
Micro-FrontendsLarge orgsIndependenceComplexity
IslandsContent sitesPerformanceLimited interactivity
Clean ArchitectureComplex logicTestabilityBoilerplate
Atomic DesignDesign systemsConsistencyCan be rigid

Decision Matrix

Team size? β”œβ”€β”€ 1-5 developers β†’ Monolithic β”œβ”€β”€ 5-15 developers β†’ Feature-Based └── 15+ or multiple teams β†’ Micro-Frontends SEO requirements? β”œβ”€β”€ Not important β†’ CSR (SPA) β”œβ”€β”€ Important β†’ SSR or SSG └── Critical β†’ SSG + Islands Performance budget? β”œβ”€β”€ TTI > 3s acceptable β†’ CSR is fine β”œβ”€β”€ TTI < 2s needed β†’ SSR + Code splitting └── TTI < 1s needed β†’ SSG + Islands

Common Combinations

ScenarioArchitectureRenderingState
Startup MVPMonolithicCSRContext + React Query
E-commerceFeature-BasedSSR/ISRRedux + React Query
Content SiteIslandsSSGMinimal (Astro)
DashboardFeature-BasedCSRZustand + React Query
EnterpriseMicro-FrontendsSSRPer-app (isolated)
Best Practices Checklist:
  • βœ… Start simple, evolve as needed
  • βœ… Choose rendering strategy based on content type
  • βœ… Separate concerns (UI, logic, data)
  • βœ… Define clear module boundaries
  • βœ… Use TypeScript for large codebases
  • βœ… Document architectural decisions
  • βœ… Monitor bundle size and performance
Warning Signs to Scale Up:
  • Merge conflicts becoming frequent
  • Hard to find where code lives
  • Changes have unexpected side effects
  • Build times > 10 minutes
  • Teams stepping on each other's toes