nilanth/laravel-react-boilerplate
This is a boilerplate, not a Composer/NPM package — there is nothing to require. The day-one workflow is clone-and-own:
git clone https://github.com/nilanth/laravel-react-boilerplate my-app
cd my-app && rm -rf .git && git init
composer install
cp .env.example .env && php artisan key:generate
# set DB_* and SANCTUM_STATEFUL_DOMAINS / SESSION_DOMAIN in .env
php artisan migrate --seed
npm install && npm run dev
Where to look first, in this order:
routes/web.php — the catch-all route that renders the single Blade view hosting the React app. Everything else is client-side.routes/api.php and app/Http/Controllers/Auth/ — the Sanctum login/register/logout endpoints you'll be extending.resources/js/app.jsx (or index.js) — router setup, Redux Provider, Ant Design ConfigProvider.resources/js/routes/ — the lazy-loaded route table; this is the file you'll edit most often.config/sanctum.php + app/Http/Kernel.php — verify EnsureFrontendRequestsAreStateful is on the api middleware group.First use case: log in with the seeded user, confirm the Sanctum cookie flow works end-to-end, then replace the demo dashboard with your first real CRUD screen. The auth scaffold is the useful part — treat the dashboard as a worked example, not code to keep.
Authentication (SPA cookie mode, not tokens). The boilerplate uses Sanctum's stateful SPA flow. Before any mutating request:
await axios.get('/sanctum/csrf-cookie');
await axios.post('/login', { email, password });
axios must be created with withCredentials: true and X-XSRF-TOKEN picked up automatically from the cookie (the default resources/js/bootstrap.js handles the header via axios.defaults.withCredentials). Guard routes with a wrapper component that reads auth state from Redux rather than firing a request per navigation — hydrate it once from /api/user on app boot.
Adding a page (the 90% task). Three coordinated edits:
// resources/js/routes/index.jsx
const Reports = React.lazy(() => import('../pages/Reports'));
<Route path="/reports" element={
<Suspense fallback={<Spin />}>
<PrivateRoute><Reports /></PrivateRoute>
</Suspense>
} />
Then a React component under pages/, and a Laravel resource controller + route under routes/api.php. Keep the route-level React.lazy boundary per page; that's the whole point of the splitting setup and it's easy to accidentally undo by importing eagerly.
Redux slice pattern. State lives in resources/js/store/. Follow the existing slice shape rather than inventing one: action types → reducer → connect()/useSelector in the page. For a new domain (e.g. reports), copy an existing slice, rename, and register the reducer in the root reducer. Keep server data-fetching in the slice's async action so loading/error flags stay consistent with the rest of the app.
Data layer. Wrap API calls in a small services/ module of axios functions (getReports(), createReport()), and have Redux thunks call those. That keeps components free of URL strings and makes it trivial to swap in axios interceptors for 401 → redirect-to-login handling.
Ant Design usage. Use <Form> with Form.Item + name props rather than controlled inputs — it handles validation and layout (Row/Col, Space) with far less code. Wrap your app in ConfigProvider once to set locale/theme globally instead of per-page.
Deployment. npm run production (Laravel Mix) or npm run build if you've migrated to Vite, then serve public/ via nginx. Nginx must try_files $uri $uri/ /index.php?$query_string so deep links like /reports/7 hit the Blade catch-all and let React Router resolve them.
npm install peer-dependency conflicts and for pinning Node (.nvmrc with Node 16/18). There will be no upstream fixes — fork means you own every CVE.SANCTUM_STATEFUL_DOMAINS must include the exact host:port you hit in the browser (localhost:8000, not 127.0.0.1), and SESSION_DOMAIN must match. Mixing localhost and 127.0.0.1 between php artisan serve and your browser is the classic failure.Authorization: Bearer headers "just in case" — Sanctum's guard will pick token mode and silently break the session flow. If you need mobile/API clients later, add HasApiTokens usage deliberately as a second path.withCredentials must be global, not per-request. Missing it on one axios instance means the CSRF cookie isn't sent and only some POSTs 419 — maddening to debug. Check bootstrap.js first.routes/web.php is last and excludes api/*.import Dashboard from './pages/Dashboard' in a shared barrel file defeats route-level splitting; check bundle output in npm run production if load times regress.bootstrap.js, a PrivateRoute component, Laravel middleware/Gates for authorization, and service providers for cross-cutting backend concerns. Keep these files thin so future framework upgrades (Laravel 9 → 11, AntD 4 → 5) remain tractable.How can I help you explore Laravel packages today?