Back to Blog
TutorialsFullstackWeb Development

Build a Fullstack App with Laravel 12, React, and TypeScript (Vite-Powered)

Mustaf Abubakar
Mustaf Abubakar
7 min read
Build a Fullstack App with Laravel 12, React, and TypeScript (Vite-Powered)

In this tutorial, you'll learn how to build a modern fullstack application using Laravel 12 as an API backend, and React + TypeScript for the frontend, powered by Vite — all inside a single project.

🧱 What We'll Use

  • Laravel 12.x – API-first PHP backend
  • React 18+ – For building a dynamic, SPA-style frontend
  • TypeScript – Type-safe JavaScript for better dev experience
  • Vite – Fast dev server and build tool, replacing Webpack
  • Single project structure – Laravel serves both the API and React frontend

📦 Step 1: Create a Laravel Project

laravel new my-app
cd my-app

This creates a new Laravel 12 project. You can also use Composer if the Laravel installer isn’t installed.

composer create-project laravel/laravel my-app
cd my-app

⚛️ Step 2: Install React + TypeScript

npm install
npm install react react-dom @vitejs/plugin-react
npm install --save-dev typescript @types/react @types/react-dom
npx tsc --init

Installs React, TypeScript, and Vite's React plugin.
npx tsc --init generates a tsconfig.json to configure TypeScript.


🔧 Configure Vite

Update vite.config.js:

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

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

This tells Vite to:

  • Compile the React entry file (app.tsx)
  • Use React plugin for JSX support
  • Enable hot reload (refresh: true)

🛠️ Update TypeScript Config

Update tsconfig.json with:

{
  "compilerOptions": {
    "jsx": "react-jsx", // Required for JSX syntax
    "module": "ESNext",
    "target": "ESNext",
    "moduleResolution": "node",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  }
}

Ensures proper TypeScript behavior with React and modern ES features.

📁 Step 3: Add React Entry Files

📄 resources/js/app.tsx

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './components/App';

const root = ReactDOM.createRoot(document.getElementById('app')!);
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

This is your main entry file that mounts the React app into the DOM.


📄 resources/js/components/App.tsx

import React from 'react';

const App: React.FC = () => (
  <div style={{ padding: '2rem', fontFamily: 'sans-serif' }}>
    <h1>🚀 Laravel + React + TypeScript is Ready!</h1>
    <p>You’re now running a fullstack Vite-powered app.</p>
  </div>
);

export default App;

A basic React component to test rendering from Laravel.

🖼️ Step 4: Load React via Blade Template

📄 resources/views/app.blade.php

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>My React App</title>
    @viteReactRefresh
    @vite('resources/js/app.tsx')
</head>
<body>
    <div id="app"></div>
</body>
</html>

This Blade view includes your compiled React app and enables HMR with Vite.

Update routes/web.php:

Route::get('/', fn() => view('app'));

This route loads your Blade view and serves as the entry point for the React SPA.

🌐 Step 5: Setup a Simple API Route

Enable Laravel’s built-in API structure:

php artisan install:api

Scaffolds Laravel's default API middleware and file structure.

Then add a test route in routes/api.php:

Route::get('/ping', function () {
    return response()->json([
        'message' => 'API is working ✅',
        'time' => now(),
    ]);
});

This route will be accessible at /api/ping and confirms the API is working.

🧪 Step 6: Run Your App Locally

# Terminal 1: Laravel backend
php artisan serve

# Terminal 2: Vite frontend (React + HMR)
npm run dev

Now you can test:

🚀 Step 7: Production Preparation

🛠️ Build Assets

npm run build

Compiles and minifies your React app into public/build.

🔐 Set Environment Variables

APP_ENV=production
APP_DEBUG=false

Disable debug mode and tell Laravel to use cached config/assets.

⚡ Optimize Laravel

php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan storage:link

Speeds up your Laravel app by caching configs, views, and routes.

📂 Final Project Structure

my-app/
├── routes/
│   ├── web.php        # Loads React view
│   ├── api.php        # API routes
├── resources/
│   ├── js/
│   │   ├── app.tsx
│   │   └── components/App.tsx
│   └── views/app.blade.php
├── public/
│   └── build/         # Production-ready assets from Vite

💡 Pro Tips

  • Use React Router for SPA-style routing inside the dashboard.
  • Add Axios to call your Laravel APIs from React.
  • Use Sanctum for token/cookie-based authentication.
  • Deploy with Laravel Forge, Docker, or any LAMP/VPS stack.

🧡 Built With

🙌 Wrap Up

You've just built a scalable, modern fullstack application using Laravel and React — with TypeScript and Vite under the hood.

This architecture is great for:

  • Admin panels
  • Dashboards
  • Hybrid web/mobile API apps
  • Anything that needs Laravel + SPA

Thanks for reading! Feel free to connect, share feedback, or expand this starter into your next big thing.


Next up: In a follow-up post, we’ll add:

  • User authentication with Sanctum
  • React Router for navigation
  • Protected routes and roles
  • Deployment tips

📦 Get the Full Source Code

Everything we covered is available here:
🔗 GitHub – Mustafaa4A/laravel-react-typescript-starter

Feel free to star the repo or fork it as your own starter!

Want to work together?

I'm always open to discussing new projects and opportunities.

Get in Touch