PHPackages                             aliziodev/laravel-next-starter-kit - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Framework](/categories/framework)
4. /
5. aliziodev/laravel-next-starter-kit

ActiveProject[Framework](/categories/framework)

aliziodev/laravel-next-starter-kit
==================================

A decoupled Laravel (API) + Next.js starter kit with Fortify + Sanctum authentication, powered by next-sanctum.

00TypeScriptCI passing

Since Jun 27Pushed todayCompare

[ Source](https://github.com/aliziodev/laravel-next-starter-kit)[ Packagist](https://packagist.org/packages/aliziodev/laravel-next-starter-kit)[ RSS](/packages/aliziodev-laravel-next-starter-kit/feed)WikiDiscussions main Synced today

READMEChangelogDependenciesVersions (1)Used By (0)

Laravel + Next.js Starter Kit
=============================

[](#laravel--nextjs-starter-kit)

[![tests](https://github.com/aliziodev/laravel-next-starter-kit/actions/workflows/tests.yml/badge.svg)](https://github.com/aliziodev/laravel-next-starter-kit/actions/workflows/tests.yml)[![lint](https://github.com/aliziodev/laravel-next-starter-kit/actions/workflows/lint.yml/badge.svg)](https://github.com/aliziodev/laravel-next-starter-kit/actions/workflows/lint.yml)[![e2e](https://github.com/aliziodev/laravel-next-starter-kit/actions/workflows/e2e.yml/badge.svg)](https://github.com/aliziodev/laravel-next-starter-kit/actions/workflows/e2e.yml)[![Packagist Version](https://camo.githubusercontent.com/9ad4e8f6db58e227d26311ccdf99ebafb7ab4f07f6322592d07fe8bda92fa9a5/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f616c697a696f6465762f6c61726176656c2d6e6578742d737461727465722d6b6974)](https://packagist.org/packages/aliziodev/laravel-next-starter-kit)[![Packagist Downloads](https://camo.githubusercontent.com/266c12f3851a2290276b1f74d6a9c462818dcc9c83186f12c54b1d4193aaeb14/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f616c697a696f6465762f6c61726176656c2d6e6578742d737461727465722d6b6974)](https://packagist.org/packages/aliziodev/laravel-next-starter-kit)[![next-sanctum](https://camo.githubusercontent.com/4547386638607aed121d46889a448f2c1e3b3c2908b4e74237fd54eb6ee7b5cb/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f6e6578742d73616e6374756d3f6c6162656c3d6e6578742d73616e6374756d)](https://www.npmjs.com/package/next-sanctum)[![License: MIT](https://camo.githubusercontent.com/08cef40a9105b6526ca22088bc514fbfdbc9aac1ddbf8d4e6c750e3a88a44dca/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d626c75652e737667)](https://github.com/aliziodev/laravel-next-starter-kit/blob/main/LICENSE)

A **decoupled** starter kit: a headless **Laravel** API and a separate **Next.js** (App Router) frontend, wired together with [Laravel Fortify](https://laravel.com/docs/fortify) + [Sanctum](https://laravel.com/docs/sanctum) and the [`next-sanctum`](https://www.npmjs.com/package/next-sanctum) client.

It mirrors the UI and feature set of the official [laravel/react-starter-kit](https://github.com/laravel/react-starter-kit), but instead of Inertia it ships an independent SPA that talks to Laravel over a **same-origin proxy** (no CORS).

Architecture
------------

[](#architecture)

 ```
flowchart LR
    subgraph client [Client]
        B["Browsercookies · CSRF"]
    end
    subgraph next ["Next.js · :3000"]
        P["Route proxyapp/api/sanctum/[...path]"]
        SC["Server ComponentsgetUser() · serverFetch()"]
    end
    subgraph api ["Laravel API · :8000"]
        L["Fortify + Sanctumroutes/api.php (auth:sanctum)"]
    end
    B -->|same-origin| P
    P -->|"forwards cookies + Origin/Referer"| L
    SC -->|server-to-server| L
```

      Loading The browser only ever talks to the **Next.js** origin. The route handler forwards requests to Laravel carrying the session cookie and `Origin`/`Referer`, so Sanctum treats the SPA as first-party (stateful) — no CORS. Server Components authenticate directly via `getUser()` / `serverFetch()` from `next-sanctum/server`.

### Login (cookie/SPA) flow

[](#login-cookiespa-flow)

 ```
sequenceDiagram
    participant B as Browser
    participant N as Next.js proxy
    participant L as Laravel (Fortify + Sanctum)
    B->>N: GET /api/sanctum/sanctum/csrf-cookie
    N->>L: forward (+ Origin/Referer)
    L-->>B: Set-Cookie XSRF-TOKEN + session
    B->>N: POST /api/sanctum/login (X-XSRF-TOKEN)
    N->>L: forward
    L-->>B: 200 authenticated — or { two_factor: true }
```

      Loading ### Auth boundaries

[](#auth-boundaries)

Protected pages live in an **`(app)` route group** whose layout calls `getUser()` once and redirects guests to `/login` — the decoupled equivalent of `Route::middleware('auth')->group(...)`; auth pages live in **`(auth)`**. Only those groups mount the Sanctum provider, so public pages (e.g. the welcome page) stay provider-free. The authoritative security boundary is the API itself (`auth:sanctum`); `proxy.ts` is only an optimistic edge fast-path.

Features
--------

[](#features)

- **Authentication** — login, registration, password reset, password confirmation
- **Two-factor authentication** (TOTP) — QR setup, confirmation, recovery codes, login challenge
- **Passkeys** (WebAuthn) — passwordless sign-in + management, via [`laravel/passkeys`](https://github.com/laravel/passkeys) and `@laravel/passkeys`
- **Email verification** — opt-in (off by default, like the official kit — see [below](#email-verification))
- **Settings** — profile, password, appearance (light/dark/system), account deletion
- **App shell** — sidebar/header layouts, breadcrumbs, user menu, dashboard
- Dark mode (`next-themes`), toasts (`sonner`), shadcn/ui (Nova preset), Tailwind v4, React 19

Requirements
------------

[](#requirements)

- PHP **8.4+** and Composer
- Node **20+** and **pnpm** (`corepack enable pnpm`)

Quick start
-----------

[](#quick-start)

```
# 1. Scaffold the project (runs key:generate + migrate automatically)
laravel new my-app --using=aliziodev/laravel-next-starter-kit
cd my-app

# 2. Install the Next.js frontend (run from the my-app root;
#    web/.env.local is created from web/.env.example automatically)
pnpm --dir web install

# 3. Run the API + queue + frontend together
composer run dev
```

Open **** and register an account. The API runs on ****.

> **Laravel installer prompts:** when `laravel new` asks *"run `npm install --ignore-scripts` and `npm run build`?"*, answer **no** — this kit's frontend lives in `web/` (pnpm) and is installed in step 2. A `tests.yml` warning is harmless (this kit's CI workflow is `e2e.yml`). Choose **Pest** when asked for a testing framework (this kit's backend tests use Pest); Laravel Boost is optional (dev-only AI tooling).
>
> The root `package.json` only delegates `dev`/`build` to `web/`, so `composer run dev` keeps working even though the installer rewrites its `dev` script to call `npm run dev`.

> Already have a clone? Run `composer run setup` once to copy env files, generate the app key, migrate, and install the web dependencies.

Project structure
-----------------

[](#project-structure)

```
.
├── app/                # Laravel application code (Fortify actions, controllers)
├── routes/
│   ├── api.php         # Sanctum-guarded API routes (/user, /account, /passkeys)
│   └── web.php         # Headless: returns JSON at / (no Blade views)
├── config/             # fortify.php, sanctum.php, passkeys.php, …
├── database/
│   └── seeders/        # DatabaseSeeder + E2eSeeder (test users)
├── package.json        # root: delegates dev/build/start/lint to web/ (no deps)
└── web/                # Next.js frontend (App Router, no src/)
    ├── app/            # root layout + (app)/ & (auth)/ route groups + /api/sanctum proxy
    ├── components/     # UI (shadcn in components/ui) + auth/settings components
    ├── layouts/        # app shell + auth page layouts
    ├── e2e/            # Playwright tests
    ├── lib/            # sanctum.ts (client config) · auth.ts (request-cached getUser)
    └── proxy.ts        # Next middleware (optimistic auth fast-path)

```

Environment
-----------

[](#environment)

Backend (`.env`):

VariablePurpose`FRONTEND_URL`Where email links (verify / reset) point back to (the SPA).`SANCTUM_STATEFUL_DOMAINS`First-party origins for cookie auth — **must** list `:3000` + `:8000`.`SESSION_DRIVER=database`Required for the cookie/SPA flow.`SESSION_COOKIE`Pinned to `laravel_session` for the proxy's cookie check.Frontend (`web/.env.local`):

VariablePurpose`NEXT_PUBLIC_SANCTUM_BASE_URL`Client base URL → the same-origin proxy (`/api/sanctum`).`SANCTUM_BASE_URL`Server-only upstream → the real Laravel origin.Security
--------

[](#security)

- **No CORS:** the browser only calls the Next.js origin; the route proxy forwards to Laravel server-side. The API is never exposed cross-origin to the browser.
- **Stateful cookie auth:** Sanctum's `statefulApi()` authenticates the SPA via an `HttpOnly` session cookie. Only origins listed in `SANCTUM_STATEFUL_DOMAINS` are treated as first-party.
- **CSRF:** every mutating request carries the `XSRF-TOKEN` cookie as an `X-XSRF-TOKEN` header; `next-sanctum` attaches it and transparently refreshes + retries once on a 419.
- **Password confirmation:** sensitive actions (managing passkeys, deleting the account, enabling/disabling 2FA) sit behind Fortify's password-confirmation window (`password.confirm`).
- **Two-factor authentication:** TOTP with a required confirmation step, single-use recovery codes, and password-confirmed enable/disable.
- **Passkeys (WebAuthn):** Fortify (&gt;= 1.37) owns the passkey routes, so the relying-party ID and `allowed_origins` are configured in `config/fortify.php` (`passkeys` key) — `allowed_origins` **must** include the SPA origin (`FRONTEND_URL`, e.g. `:3000`) since the browser runs the ceremony there. Registration requires resident keys + user verification, management is password-confirmed, and the endpoints are rate limited (`6,1`). Use **`localhost`** (not `127.0.0.1`) in development so the origin matches the relying-party ID.
- **Rate limiting:** Fortify throttles login attempts (5/min per email + IP); passkey endpoints use `throttle:6,1`.
- **API tokens:** Sanctum personal-access tokens are available for mobile / third-party clients via `Authorization: Bearer ` (the SPA itself uses cookies).
- **Going to production:** serve both apps over **HTTPS**; set `APP_URL`, `FRONTEND_URL`, and `SANCTUM_STATEFUL_DOMAINS` to your real domains; set `SESSION_DOMAIN` (e.g. `.example.com`) for cross-subdomain cookies; set `APP_DEBUG=false`; and configure a real mailer.

Testing
-------

[](#testing)

End-to-end (Playwright, Chromium) — drives the full stack and covers login, invalid credentials, registration, logout, the **passkey ceremony** (register + passwordless sign-in, via a CDP virtual authenticator), and **2FA** (enable + login challenge, via a computed TOTP). No real device is needed.

```
pnpm --dir web exec playwright install chromium   # first time only
pnpm --dir web test:e2e
```

Locally the suite reuses already-running dev servers; in CI it boots them itself. GitHub Actions runs it on every push / PR (`.github/workflows/e2e.yml`).

Backend (Pest):

```
composer test
```

Lint &amp; format:

```
pnpm --dir web lint && pnpm --dir web format:check   # Next.js / TypeScript
vendor/bin/pint --test                               # PHP (Laravel Pint)
```

All three suites run in **GitHub Actions** on every push / PR — `tests.yml` (Pest, PHP 8.4/8.5), `lint.yml` (Pint + ESLint + Prettier), and `e2e.yml` (Playwright).

Email verification
------------------

[](#email-verification)

Email verification is **off by default**, matching the official Laravel starter kit. To enable it:

1. In `web/lib/email-verification.ts`, set `MUST_VERIFY_EMAIL = true`.
2. In `app/Models/User.php`, uncomment the `MustVerifyEmail` import and add it to the `implements` list so Fortify sends verification emails.

The verify-email pages and the resend flow ship ready to use; the flag simply gates the UI enforcement.

License
-------

[](#license)

MIT.

###  Health Score

20

—

LowBetter than 13% of packages

Maintenance65

Regular maintenance activity

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity11

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/187039973?v=4)[Alizio](/maintainers/aliziodev)[@aliziodev](https://github.com/aliziodev)

---

Top Contributors

[![aliziodev](https://avatars.githubusercontent.com/u/187039973?v=4)](https://github.com/aliziodev "aliziodev (9 commits)")

### Embed Badge

![Health badge](/badges/aliziodev-laravel-next-starter-kit/health.svg)

```
[![Health](https://phpackages.com/badges/aliziodev-laravel-next-starter-kit/health.svg)](https://phpackages.com/packages/aliziodev-laravel-next-starter-kit)
```

###  Alternatives

[laravel/socialite

Laravel wrapper around OAuth 1 &amp; OAuth 2 libraries.

5.7k104.3M832](/packages/laravel-socialite)[laravel/dusk

Laravel Dusk provides simple end-to-end testing and browser automation.

1.9k38.6M289](/packages/laravel-dusk)[pinguo/php-msf

Pinguo Micro Service Framework For PHP

1.7k4.2k](/packages/pinguo-php-msf)[nineinchnick/edatatables

Grid widget for the Yii Framework, wrapper for the DataTables jQuery plugin

173.2k](/packages/nineinchnick-edatatables)[link-cloud/fast-hyperf

LinkCloud Fast Hyperf

241.2k1](/packages/link-cloud-fast-hyperf)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
