Frontend structure conventions for Laravel Inertia React applications based on Spatie's production practices. Use when creating, scaffolding, or reviewing frontend code in a Laravel Inertia React project. Triggers on creating React components, pages, modules, organizing frontend directories, setting up Inertia pages, structuring a React frontend within Laravel, or when the user asks about frontend file organization in an Inertia app.
Based on Spatie's conventions for structuring production Laravel Inertia React applications.
Four base directories under resources/js:
resources/js/
├── common/ # Generic, reusable code portable across projects
├── modules/ # Project-specific code shared across multiple pages
├── pages/ # Inertia page components
└── shadcn/ # Auto-generated shadcn/ui components (if used)
common vs modules: ask "Does it relate to a domain or feature?" If yes → modules. If it's generic and project-agnostic → common.
PascalCaseButton.tsxAuthContext.tsxcamelCase (e.g. useAuth.ts, formatDate.ts)kebab-case (e.g. date-picker/, user-management/)Small modules have a few top-level files. Larger modules organize by type:
modules/agenda/
├── components/
├── contexts/
├── constants/
├── helpers/
├── hooks/
├── stores/
└── types.ts # or types/ directory if large
The common/ directory follows the same structure.
Pages mirror the URL structure. Components are suffixed with Page.
pages/
├── layouts/ # Global layouts
├── admin/
│ ├── layouts/ # Section-specific layouts
│ ├── users/
│ │ ├── components/ # Page-specific partials
│ │ ├── helpers/
│ │ ├── IndexPage.tsx
│ │ └── EditPage.tsx
│ └── DashboardPage.tsx
└── auth/
├── LoginPage.tsx
└── RegisterPage.tsx
Use function declarations (not const arrow functions) and named exports exclusively:
// Correct
export function Button({ variant, className }: ButtonProps) {
return <button className={cn(variant, className)}>Click</button>;
}
// Wrong: const + default export
const Button = ({ variant }) => { ... };
export default Button;
One component per file. No barrel files (index.ts re-exports).
Two blocks separated by a blank line: library imports first, then application imports. Use absolute paths with aliases (@/):
import { useState } from "react";
import { cn } from "@/common/helpers/cn";
import { useAgenda } from "@/modules/agenda/hooks/useAgenda";
import { AgendaItem } from "@/modules/agenda/components/AgendaItem";
Sort alphabetically, with className and children last:
interface DialogProps {
onClose: () => void;
open: boolean;
title: string;
className?: string;
children: React.ReactNode;
}
Use Tailwind. Single app.css for most projects. Larger projects split into:
resources/css/
├── base/
├── components/
└── utilities/
For apps with distinct sections (e.g. admin/client), introduce apps/:
resources/js/
├── common/ # Shared across all zones
├── modules/ # Global modules shared across zones
├── apps/
│ ├── admin/
│ │ ├── modules/ # Admin-specific modules
│ │ ├── pages/
│ │ └── app.tsx
│ └── client/
│ ├── modules/ # Client-specific modules
│ ├── pages/
│ └── app.tsx
└── shadcn/
Abstract shadcn components into simpler, project-specific implementations rather than using the low-level API directly in application code. Place abstractions in common/ or modules/ as appropriate.