Introduction

When you’re building a modern web app, one thing is clear: the backend and frontend have to talk seamlessly. It’s like a kitchen and dining hall:

  • Laravel (backend) is the chef preparing data.

  • React (frontend) is the waiter delivering it beautifully to users.

In this guide, we’ll build a RESTful API using Laravel 12 and connect it with React 19. You’ll get hands-on steps (setup, code, best practices) and understand why we pick these versions.

Let’s roll up our sleeves.


Why Laravel 12 + React 19?

You might ask: “Why not Laravel 11 or React 18?” Good question. Here’s what makes 12 & 19 attractive:

Laravel 12

  • Released on February 24, 2025

  • It focuses on maintenance, minimal breaking changes, and updating dependencies.

  • It introduces new starter kits for React, Vue, and Livewire (using Inertia, shadcn UI, TypeScript, etc.).

  • It continues support for PHP 8.2 – 8.4 and has an extended window for bug fixes & security fixes.

So using Laravel 12 means you’re future-proof, getting the latest defaults, and not stuck in old patterns.

React 19

  • React v19 became stable on December 5, 2024

  • It adds Actions, a powerful new paradigm for async state updates (you can pass async functions to transitions).

  • New hooks and APIs: useActionState, useFormStatus, useOptimistic, use etc.

  • Many experimental features from React 18 are now stabilized in 19.

So React 19 gives you a cleaner, more expressive way to handle async UI transitions and state.

In short: Laravel 12 + React 19 means you’re on bleeding edge, stable, modern defaults.

Step 1: Set Up Laravel 12

First, create the project using Laravel 12:
composer create-project laravel/laravel:^12.0 laravel-api
cd laravel-api

Configure Database

In .env:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_DATABASE=react_api
DB_USERNAME=root
DB_PASSWORD=

Then run:

php artisan migrate

Your Laravel 12 backend is alive.

Step 2: Plan the API

Let’s build a simple Task Manager API with CRUD:

  • Create a task

  • Get tasks

  • Update a task

  • Delete a task

That aligns perfectly with REST principles.

Step 3: Model & Migration

Generate:

php artisan make:model Task -m

In the migration file:

public function up()
{
Schema::create(‘tasks’, function (Blueprint $table) {
$table->id();
$table->string(‘title’);
$table->text(‘description’)->nullable();
$table->boolean(‘is_completed’)->default(false);
$table->timestamps();
});
}

Then:

php artisan migrate
 
Now the tasks table is ready.

Step 4: Resource Controller

Generate:

php artisan make:controller TaskController –resource

 
In TaskController.php:
 

namespace App\Http\Controllers;

use App\Models\Task;
use Illuminate\Http\Request;

class TaskController extends Controller
{
public function index()
{
return response()->json(Task::all(), 200);
}

public function store(Request $request)
{
$request->validate([
‘title’ => ‘required|string|max:255’
]);

$task = Task::create($request->all());
return response()->json($task, 201);
}

public function show(Task $task)
{
return response()->json($task, 200);
}

public function update(Request $request, Task $task)
{
$task->update($request->all());
return response()->json($task, 200);
}

public function destroy(Task $task)
{
$task->delete();
return response()->json(null, 204);
}
}

We validate inputs so garbage doesn’t sneak in.

Step 5: API Routes

In routes/api.php:

use App\Http\Controllers\TaskController;

Route::apiResource(‘tasks’, TaskController::class);

Laravel wires:

  • GET /api/tasks

  • POST /api/tasks

  • PUT /api/tasks/{id}

  • DELETE /api/tasks/{id}

Step 6: Test via Postman

Use Postman or Insomnia to verify:

  • POST /api/tasks → create

  • GET /api/tasks → list

  • PUT /api/tasks/{id} → update

  • DELETE /api/tasks/{id} → delete

Once that’s working, you’re good to move to the frontend.

Step 7: Set Up React 19

Create the frontend project:

npm init react-app react-frontend
cd react-frontend
npm install react@19 react-dom@19
npm start

Or using a more modern tool (Vite, etc.) ensure React 19 is your installed version.

Install Axios:

npm install axios

Step 8: API Service Layer

In src/services/taskService.js:

import axios from ‘axios’;

const API_URL = “http://127.0.0.1:8000/api/tasks”;

export const getTasks = () => axios.get(API_URL);
export const createTask = (task) => axios.post(API_URL, task);
export const updateTask = (id, task) => axios.put(`${API_URL}/${id}`, task);
export const deleteTask = (id) => axios.delete(`${API_URL}/${id}`);

This keeps calls organized and your components clean.

Step 9: Build React UI with React 19 Features

Here’s a sample component using React 19 patterns:

import React, { useEffect, useState, startTransition } from ‘react’;
import { getTasks, createTask, updateTask, deleteTask } from ‘./services/taskService’;

function TaskApp() {
const [tasks, setTasks] = useState([]);
const [title, setTitle] = useState(“”);

useEffect(() => {
loadTasks();
}, []);

const loadTasks = () => {
getTasks().then(res => setTasks(res.data));
};

const handleAdd = () => {
if (!title.trim()) return;
// Use React 19’s transition
startTransition(async () => {
await createTask({ title });
await loadTasks();
setTitle(“”);
});
};

const handleToggle = (task) => {
startTransition(async () => {
await updateTask(task.id, { …task, is_completed: !task.is_completed });
loadTasks();
});
};

const handleDelete = (id) => {
startTransition(async () => {
await deleteTask(id);
loadTasks();
});
};

return (
<div>
<h1>Task Manager (React 19)</h1>
<input
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder=”Enter a task”
/>
<button onClick={handleAdd}>Add</button>

<ul>
{tasks.map(task => (
<li key={task.id}>
{task.title} — {task.is_completed ? “Done” : “🕓 Pending”}
<button onClick={() => handleToggle(task)}>Toggle</button>
<button onClick={() => handleDelete(task.id)}>Delete</button>
</li>
))}
</ul>
</div>
);
}

export default TaskApp;

Notice we wrap async operations in startTransition (a React 19/18 concept) for smoother UI updates.

Later, you can incorporate new hooks such as useActionState, useOptimistic, useFormStatus, etc., for more advanced patterns.

Step 10: Handle CORS

Since frontend (React 19) and backend (Laravel 12) might run on different ports, configure CORS.

Install the package:

composer require fruitcake/laravel-cors

In config/cors.php, allow React’s origin (e.g. http://localhost:3000).

Step 11: Secure Your API

Security is key. Consider:

  1. Authentication: Use Laravel Sanctum or the new starter kit features in Laravel 12 (React starter kit supports auth out of the box).

  2. Validation: Already used in store. Also validate in update.

  3. Rate Limiting: Throttle to prevent abuse.

  4. Error Handling: Return consistent JSON errors with HTTP status codes.

Step 12: Best Practices

  • Use Laravel API Resources to format JSON.

  • Version your API (e.g. /api/v1/tasks) so future changes don’t break older clients.

  • Paginate when the dataset grows.

  • Logging/Monitoring: Use Laravel Telescope (or similar) for API visibility.

  • Use the new starter kit in Laravel 12 for React + auth boilerplate to avoid rewriting basic plumbing.

Step 13: Deployment

  • Frontend (React 19): Deploy to Vercel, Netlify, or any static host.

  • Backend (Laravel 12): Deploy to Forge, a VPS, or platforms like Heroku.

  • Database: Use managed DB (RDS, etc.).

  • Keep .env safe and out of version control.

Real-World Use Cases

  • SaaS apps where React 19’s transitions simplify form-heavy UIs.

  • Dashboards with real-time updates.

  • E-commerce: Laravel 12 handles APIs for products/orders, React 19 handles cart, UI transitions, etc.

Conclusion

Using Laravel 12 + React 19 lets you start with the most current, stable versions available. You get:

  • Laravel 12’s refined defaults, starter kits, modern dependency updates.

  • React 19’s new APIs and better async UI handling.

In this guide, you:

  • Set up Laravel 12 and built REST APIs.

  • Tested endpoints in Postman.

  • Set up React 19 and consumed the APIs.

  • Handled CORS, validation, and security.

  • Touched on performance & best practices.

This stack isn’t just for toy projects. it’s a strong foundation for real-world, production apps. Contact Us