Skip links
Laravel with React

How to use Laravel with React for creating a modern application — Step-by-step complete guide

Modern web projects demand both a reliable backend and a responsive, interactive frontend. Combining Laravel’s mature server-side framework with React’s fast, component-driven UI gives you the best of both worlds: a robust API, clear business logic and database handling from Laravel, alongside a fluid, stateful user experience from React.

This guide walks you through building a Laravel application that contains an integrated React front end. This guide includes: a quick starter-kit path for speed, and a lean manual path for control. Each step is practical — small commands you can run locally, short code snippets you can copy, and focused troubleshooting for the common issues you’ll meet. I’ll also outline authentication options and route helpers that expose named Laravel routes to React.

 Why use Laravel?

Laravel is an opinionated, well-documented PHP framework that’s built for developer productivity.

Key advantages:

      • Rapid development: Artisan CLI, routing, and scaffolding reduce boilerplate so you build features quicker.

      • Ecosystem: Eloquent ORM, Queues, Jobs, Events, and first-party packages like Sanctum and Horizon cover common needs.

      • Clear structure: Conventions and folder organisation make medium to large apps easier to maintain.

      • Security & testing: Built-in protections (CSRF, authentication helpers) and PHPUnit integration make it straightforward to write safe, testable code

    Use Laravel when you want a dependable backend that handles data, authentication, email, queues and APIs without reinventing the wheel.

    Why use React?

    React is a lightweight, component-based library for building interactive UIs.

    What it offers:

        • Component-driven UI: Build reusable components that simplify complex interfaces.

        • Fast rendering: Virtual DOM minimises costly DOM updates for snappy behaviour.

        • Ecosystem & tooling: Rich ecosystem (react-router, react-query, SWR) and modern build tools (Vite) for a great dev experience.

        • Flexible state management: Choose the best fit — Context, Redux, Zustand, or React Query for server state.

        • Large community & resources: Extensive tutorials, packages and community examples for nearly any UI pattern.

      Choose React when you need a responsive, interactive front end with easy reuse of UI patterns and strong tooling support.

      Why use TailwindCSS?

      TailwindCSS is a utility-first CSS framework that encourages composing styles with small, descriptive classes rather than building large handcrafted CSS files.

      Key advantages:

          • Fast UI prototyping: Build layouts quickly by composing utilities (no lengthy CSS overrides).

          • Small final CSS: Purging unused classes produces tiny production bundles.

          • Component-friendly: Works well with React components — class names live alongside markup.

          • Consistent design system: Easy to enforce spacing, colour and typography scales across teams.

          • Good toolchain fit: Tailwind integrates smoothly with Vite (default in modern Laravel) and with Laravel’s asset pipeline.

        TailwindCSS speeds up UI development, keeps styles consistent across the app and makes responsive design straightforward.

        Step-by-Step Implementation Process

        This section sets up a single Laravel project containing a React front end (Vite + resources/js). Follow either the Starter kit route for quick scaffolding or the Manual route for minimal, explicit control. Pick the path that suits.

        1. Create the Laravel project (common to both paths)

         # from your working folder
        composer create-project laravel/laravel laravel-react-app

          # Navigate to project directory

          cd laravel-react-app

         # create environment and app key
         cp .env.example .env

           php artisan key:generate

           # Start your PHP dev server

          php artisan serve

        2.1. Starter kit path (fast scaffolding)

         # install Breeze (dev requirement)

           composer require laravel/breeze –dev

           # install the React scaffolding (Breeze will publish basic React + Vite setup)

           php artisan breeze:install react

            # install JS deps and build

           npm install

           npm run dev

           # run migrations (creates users table etc.)

            php artisan migrate

        What this gives you

            • A ready Vite configuration, resources/js React entry points and example components.

            • Basic authentication scaffolding (login/register) wired into the Laravel backend and React frontend (worth studying to understand the flow).

            • Tailwind is usually wired in by the Breeze scaffolding; if not, follow the Tailwind steps from Section 1.

          Notes

              • Breeze is lightweight and ideal if you want an opinionated, minimal starting point.

              • If you prefer server-driven UI, Jetstream (with Inertia) is an alternative, but Jetstream adds more complexity — stick to Breeze for a simpler React + Laravel app.

            2.2. Install node dependencies (React + Vite helper for Laravel)

             # install React

              npm install react react-do

              # install Vite & the Laravel Vite plugin (dev tools)

              npm install –save-dev vite laravel-vite-plugin

            Note: Modern Laravel projects already include laravel-vite-plugin in their package.json. If your project already has package.json with Vite, you do not need to re-install.

            3. Create a Vite React entry

            Create resources/js/app.jsx (simple bootstrap):

             // resources/js/app.jsx

              import ‘../css/app.css’;

              import React from ‘react’; 

              import { createRoot } from ‘react-dom/client’;

              function App() { 

              return (

              <div className=”p-6″>

              <h1 className=”text-2xl font-bold”>Laravel + React — single app</h1>

              <p className=”mt-2″>Hello from React inside Laravel.</p>

              </div> 

               );

               }

              const el = document.getElementById(‘app’);

              if (el) createRoot(el).render(<App />);

            Create a Blade file to mount the app (resources/views/app.blade.php):

            // resources/views/app.blade.php

              <!doctype html>

              <html>

               <head>

              <meta charset=”utf-8″ />

               <title>Laravel + React</title>

              @vite(‘resources/js/app.jsx’)

              </head>

              <body> 

              <div id=”app”></div>

              </body>

              </html>

            Point the route to the view (if not done already):

             // route/web.php

               Route::get(‘/’, function () {

               return view(‘app’);

                });

            4. Ensure vite.config.js is configured

            A minimal vite.config.js(if missing):

             // vite.config.js

              import { defineConfig } from ‘vite’;

              import laravel from ‘laravel-vite-plugin’;

              export default defineConfig({

              plugins: [

                laravel({

               input: [‘resources/css/app.css’, ‘resources/js/app.js’],

               refresh: true,

              }),

              ],

              });

            5. Add npm scripts if not present

            In package.json ensure you have:

            // package.json

              “scripts”: {

              “build”: “vite build”,

              “dev”: “vite”

              },

              Then run:

              npm install

              npm run dev

            Visit http://127.0.0.1:8000.

            6. Environment variables for client (Vite)

            Add an API URL for the client build if you call your own API (use Vite prefixed variables):

             // .env

              VITE_API_URL=”${APP_URL}:8000″

            In React use: import.meta.env.VITE_API_URL.

            7. Install Tailwind (if missing)

            If Tailwind wasn’t added, run:

            npm install -D tailwindcss postcss autoprefixer

            npx tailwindcss init -p

            Add @tailwind directives in resources/css/app.css and import ../css/app.css in your app.jsx as shown above.

            Laravel API + React interaction

            When you’re learning how Laravel and React work together, the fastest way to get momentum is a small, working demo. Below we’ll add a tiny JSON endpoint that returns dummy posts and a lean React component that fetches and displays them — all inside the same Laravel project. No databases, no migrations, no fuss. Later you can replace the dummy route with a controller that talks to Eloquent when you’re ready.

            This is intentionally small: the goal is a working end-to-end example you can run in a few minutes and then extend.

            1. Create a JSON API endpoint (server-side)
            Rather than scaffolding whole models and migrations, we’ll add a compact route that returns hard-coded data. It keeps the example focused and easy to understand.

            Add this to routes/api.php:

            // routes/api.php

              use Illuminate\Http\Request;

              use Illuminate\Support\Facades\Route;

              Route::get(‘/posts’, function (Request $request) {

              return response()->json([

               [‘id’ => 1, ‘title’ => ‘Welcome to Laravel + React’, ‘body’ => ‘A simple demo post.’],

               [‘id’ => 2, ‘title’ => ‘Second post’, ‘body’ => ‘More demo content here.’],

               ]);

                });

            Note: If you can’t find routes/api.php then run  php artisan install:api

            2. Create a React component to fetch the posts
            Here’s a short, friendly React component PostsList.jsx that requests the demo posts and renders them.

            // resources/js/components/PostsList.jsx

              import React, { useEffect, useState } from ‘react’;

              export default function PostsList() {

              const [posts, setPosts] = useState(null);

              const base = import.meta.env.VITE_API_URL || ”;

                useEffect(() => {

               (async () => {

                try {

                 const res = await fetch(`${base}/api/demo-posts`);

                 const data = await res.json();

                  setPosts(data);

                 } catch (e) {

                   console.error(‘Could not load posts’, e);

                   setPosts([]);

                 }

                 })();

                 }, [base]);

               if (!posts) return <div className=”p-4″>Loading posts…</div>;

               if (posts.length === 0) return <div className=”p-4″>No posts found.</div>;

               return (

               <div className=”space-y-4″>

                {posts.map(p => (

                 <article key={p.id} className=”p-4 bg-white rounded shadow”>

                  <h3 className=”text-lg font-semibold”>{p.title}</h3>

                  <p className=”text-sm text-gray-600 mt-1″>{p.body}</p>

                 </article>

                 ))}

               </div>

                );

                }

               // resources/js/app.jsx

               import ‘../css/app.css’;

               import React from ‘react’;

                import { createRoot } from ‘react-dom/client’;

                import PostsList from ‘./components/PostsList’;

                function App() {

                return (

                <div className=”min-h-screen bg-gray-50 p-6″>

                 <div className=”max-w-2xl mx-auto”>

                   <h1 className=”text-2xl font-bold mb-4″>Demo: Laravel + React</h1>

                <PostsList />

                  </div>

               </div>

              );

            }

            const el = document.getElementById(‘app’);

            if (el) createRoot(el).render(<App />);

            Conclusion & next steps — take it further

            You now have a small, working example of a React front end living inside a Laravel app: a JSON API endpoint, an integrated React frontend component and a clear path to expand this into a full application. Below are short, practical next actions you can take, plus a few recommended tools (Sanctum, Ziggy) and resources to accelerate development.

            Future Enhancements

                • Replace the dummy route with a controller that returns Eloquent data.

                • Add a basic Post model and migration when you’re ready to persist content.

                • Wire up simple authentication (Sanctum) for protected endpoints.

                • Add a small UI state pattern (Context or React Query) to manage user/session state.

                • Build a production bundle (npm run build) and test serving the assets from Laravel’s public/ folder.

              Short checklist for production readiness

                  • Validate all API responses and add consistent error handling.

                  • Configure CORS and cookie settings if your front end and API are on different origins.

                  • Ensure tailwind.config content paths are correct so production CSS is purged.

                  • Run php artisan config:cache and route:cache during deploy (if appropriate).

                Recommended extras (what they are & why use them)

                Laravel Sanctum — simple, secure authentication for SPAs
                Sanctum provides first-party support for cookie-based authentication (ideal when front end and backend share a domain) and token-based APIs. It’s lightweight, well-documented and removes much of the painful plumbing for login/CSRF flows. Use Sanctum when you want straightforward session-style auth for your SPA without the complexity of OAuth.

                Ziggy — use Laravel named routes in JavaScript
                Ziggy exports your Laravel named routes into JavaScript, letting you call route(‘posts.show’, id) from React rather than hard-coding URLs. It keeps front-end links in sync with backend route changes and reduces brittleness when refactoring routes.

                Helpful resources

                    • Laravel documentation — Routing, API Resources, Sanctum and Vite integration.

                    • React docs — Hooks, Suspense and best practices.

                    • TailwindCSS — installation, JIT usage and recommended plugins.

                    • Ziggy (package docs) — quick setup and examples.

                    • Community tutorials & example repos — search for “Laravel Vite React example” for real-world examples.

                  FAQs

                  Can Laravel be used with React?
                  Yes — absolutely. Laravel makes an excellent backend for a React front end: Laravel handles routing, business logic and the API, while React provides a fast, componentised UI. In a single-app setup (React inside resources/js) you keep one repo and simpler deployment while still getting a decoupled frontend.

                  Laravel vs React — which should I use?
                  They’re not alternatives. Laravel is a server-side PHP framework for APIs and app logic; React is a client-side UI library for building interactive interfaces. Use Laravel for backend concerns and React for the UI — together they form a modern full-stack stack.

                  Should I use a starter kit (Breeze/Jetstream) or set up manually?
                  Starter kits like Laravel Breeze (or Jetstream for extra features) are ideal when you want to get up and running quickly — they scaffold auth, Vite/Tailwind and basic UI so you can focus on features; choose the manual route when you need minimal dependencies or fine-grained control.

                  Common problems & fixes

                  · If React shows the @vitejs/plugin-react can't detect preamble error, ensure @viteReactRefresh appears before @vite() in your Blade.

                  · If the fetch returns network errors in dev, check VITE_API_URL points to the Laravel server (e.g. http://127.0.0.1:8000) and that php artisan serve is running.

                  · If you prefer to call /api/posts without VITE_API_URL, change the fetch in PostsList.jsx to fetch('/api/posts') — this will work when the page is served from the same origin as the API (production static build served from Laravel public).

                  · Open Network tab in devtools to inspect the request URL and response.

                  Laravel with React
                  This website uses cookies to improve your web experience.
                  See your Privacy Settings to learn more.
                  Home
                  Account
                  Cart
                  Search
                  View
                  Drag