How to Set Up React with Laravel 12 Without Starter Kits: A Complete Guide

September 10, 2025

 Building modern web applications often requires combining a powerful backend framework with a dynamic frontend library. Laravel 12 and React make an excellent pair, offering robust server-side capabilities alongside reactive user interfaces. While Laravel provides starter kits like Breeze and Jetstream, sometimes you need more control over your setup.
 
In this comprehensive guide, I'll walk you through setting up React with Laravel 12 from scratch, giving you complete control over your application architecture.
 

Why Choose React with Laravel 12?

 
Before diving into the setup, let's understand why this combination works so well:
 

  • Laravel 12 provides a robust API backend with excellent developer experience
  • React offers component-based UI development with excellent performance
  • Vite (Laravel's default build tool) provides fast hot module replacement
  • Complete separation of frontend and backend concerns
  • Flexibility to customize your stack exactly as needed


Prerequisites

 
Make sure you have the following installed:
 

  • PHP 8.2 or higher
  • Composer
  • Node.js 18 or higher
  • npm or yarn


Step-by-Step Setup

 

Step 1: Create a Fresh Laravel 12 Project

 
Start by creating a new Laravel project:
 

composer create-project laravel/laravel your-app-name
cd your-app-name


This gives us a clean Laravel installation without any frontend scaffolding.
 

Step 2: Install Node.js Dependencies

 
Install the necessary packages for React and build tools:
 

npm install react react-dom @vitejs/plugin-react
npm install -D @types/react @types/react-dom


These packages provide:
 

  • react and react-dom: Core React libraries
  • @vitejs/plugin-react: Vite plugin for React support
  • @types/*: TypeScript definitions for better IDE support


Step 3: Configure Vite for React

 
Update your vite.config.js file to support React:
 

 
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import react from '@vitejs/plugin-react-swc';
import tailwindcss from '@tailwindcss/vite'


export default defineConfig({
    plugins: [
        react(),
        laravel({
            input: ['resources/css/app.css', 'resources/js/app.jsx'],
            refresh: true,
        }),
        tailwindcss(),
    ],
});


Key changes:
 

  • Added React plugin
  • Changed entry point from app.js to app.jsx
  • Enabled hot module replacement with refresh: true


Step 4: Set Up React Entry Point

 
Rename resources/js/app.js to resources/js/app.jsx and replace its contents:
 

import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './components/App';
import '../css/app.css';

const container = document.getElementById('app');
const root = createRoot(container);
root.render(<App />);


This file:
 

  • Imports React and the new createRoot API
  • Imports our main App component
  • Renders the React app into the DOM element with id "app"


Step 5: Create Your First React Component

 
Create a directory resources/js/components/ and add App.jsx:
 

import React, { useState } from 'react';

function App() {
    const [count, setCount] = useState(0);

    return (
        <div className="min-h-screen bg-gray-100 flex items-center justify-center">
            <div className="bg-white p-8 rounded-lg shadow-md">
                <h1 className="text-3xl font-bold text-gray-800 mb-4">
                    React + Laravel 12
                </h1>
                <div className="space-y-4">
                    <p className="text-gray-600">Count: {count}</p>
                    <div className="space-x-2">
                        <button
                            onClick={() => setCount(count + 1)}
                            className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
                        >
                            Increment
                        </button>
                        <button
                            onClick={() => setCount(count - 1)}
                            className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded"
                        >
                            Decrement
                        </button>
                    </div>
                </div>
            </div>
        </div>
    );
}

export default App;


This creates a simple counter component to verify everything works correctly.
 

Step 6: Update Your Blade Template

 
Create or update resources/views/app.blade.php:
 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>React + Laravel</title>
    @viteReactRefresh 
    @vite(['resources/css/app.css', 'resources/js/app.jsx'])
</head>
<body>
    <div id="app"></div>
</body>
</html>


Important points:
 

  • The @vite directive loads our compiled assets
  • The div with id "app" is where React will mount
  • We're loading both CSS and JSX files


Step 7: Set Up Routes

 
Update routes/web.php to handle client-side routing:
 

<?php

use Illuminate\Support\Facades\Route;

Route::get('/{any}', function () {
    return view('app');
})->where('any', '.*');


This catch-all route ensures that all requests serve your React application, enabling client-side routing.
 

Step 9: Build and Run

 
Start both development servers:
 

# Terminal 1: Laravel development server
php artisan serve

# Terminal 2: Vite development server
npm run dev


Visit http://localhost:8000 to see your React + Laravel application in action!
 

Setting Up API Integration

 
To connect your React frontend with Laravel's API, first create API routes in routes/api.php:
 

<?php

use Illuminate\Support\Facades\Route;

Route::get('/test', function () {
    return response()->json(['message' => 'Hello from Laravel API!']);
});


Then in your React components, you can fetch data:
 

useEffect(() => {
    fetch('/api/test')
        .then(response => response.json())
        .then(data => console.log(data));
}, []);


Final Project Structure

 
Your project should now look like this:
 

your-app-name/
├── resources/
│   ├── js/
│   │   ├── components/
│   │   │   └── App.jsx
│   │   └── app.jsx
│   ├── css/
│   │   └── app.css
│   └── views/
│       └── app.blade.php
├── routes/
│   ├── web.php
│   └── api.php
├── vite.config.js
└── package.json


Next Steps

 
Now that you have a solid foundation, you can:
 

  1. Add React Router for client-side navigation
  2. Set up state management with Redux or Zustand
  3. Create API endpoints in Laravel for your React components
  4. Add authentication using Laravel Sanctum
  5. Implement real-time features with Laravel Broadcasting


Conclusion

 
Setting up React with Laravel 12 manually gives you complete control over your application architecture. This approach is perfect when you need:
 

  • Custom build configurations
  • Specific package versions
  • Complete separation of concerns
  • Full understanding of your stack


While starter kits are convenient, this manual setup ensures you understand every piece of your application and can customize it exactly to your needs.
 
The combination of Laravel's robust backend capabilities with React's dynamic frontend creates a powerful foundation for modern web applications. With hot module replacement from Vite, you'll have an excellent developer experience that scales with your project's complexity.
 
Happy coding! 🚀
 
 
Have questions about this setup? Feel free to reach out or check the Laravel and React documentation for more advanced configurations.

Laravel 12 React js vite