Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Jetstream Laravel Package

laravel/jetstream

Laravel Jetstream is a starter kit for Laravel 11.x and prior that scaffolds authentication, registration, profile management, API tokens, teams, and session management using Livewire or Inertia with Tailwind CSS.

View on GitHub
Deep Wiki
Context7

Getting Started

Check the compatibility window first. The README states Jetstream is the starter kit for Laravel 11.x and prior; for Laravel 12+ the recommendation is the new kits at laravel.com/starter-kits. Jetstream is effectively in maintenance — it's the right call for an existing Laravel ≤11 app that already uses it, or for a team that specifically wants the Livewire/Inertia + teams + Sanctum-tokens bundle. It is not a sensible greenfield choice in 2026.

composer require laravel/jetstream
php artisan jetstream:install livewire      # or: inertia
npm install && npm run build
php artisan migrate

The installer accepts feature flags (--teams, --api, --dark, --verification, --ssr, --pest, --composer=..., --force); the stack argument is validated, so a typo fails fast rather than half-scaffolding. After install, verify config/jetstream.php rather than trusting your mental model of what was generated.

Where to look first, in this order:

  1. config/jetstream.php — which features are on: Features::termsAndPrivacyPolicy(), profilePhotos(), api(), teams(['invitations' => true]), accountDeletion(), plus profile_photo_disk.
  2. config/fortify.php — registration, email verification, 2FA, password reset, and the features list that gates the auth routes. Jetstream delegates all authentication to Fortify; half of "Jetstream isn't doing X" is actually a Fortify config question.
  3. app/Providers/JetstreamServiceProvider.php — roles, permissions, API token defaults, model overrides.
  4. app/Providers/FortifyServiceProvider.php — views, login rate limiter, action bindings.
  5. app/Actions/Fortify/* and app/Actions/Jetstream/* — the mutation logic you'll actually be editing.

First useful task: log in, open /user/profile, and trace one request end-to-end — e.g. change your name and watch UpdateUserProfileInformation fire, then confirm the HasProfilePhoto trait drives the avatar. That single loop teaches you the Jetstream/Fortify/Actions split faster than reading the docs.

php artisan route:list --path=user
php artisan route:list --path=teams

Implementation Patterns

Customize by swapping actions, not by editing vendor code. Every Jetstream/Fortify action is resolved from the container, so override with a binding:

// app/Providers/JetstreamServiceProvider.php
public function boot(): void
{
    $this->app->singleton(
        \App\Actions\Fortify\CreateNewUser::class,
        \App\Actions\Fortify\CreateNewUserWithConsent::class
    );
}

This is the standard hook for "add a field to registration", "assign a default role", "notify Slack on team creation".

Roles and permissions are declared, not discovered. In JetstreamServiceProvider::boot():

Jetstream::defaultApiTokenPermissions(['read']);

Jetstream::permissions(['read', 'create', 'update', 'delete']);

Jetstream::role('admin', 'Administrator', ['read', 'create', 'update', 'delete'])
    ->description('Full access to the team.');

Jetstream::role('editor', 'Editor', ['read', 'create', 'update'])
    ->description('Can write content.');

Then check with $user->hasTeamPermission($team, 'update') and $user->tokenCan('update') for API tokens. Use Jetstream::formatPermissionsUsing(fn ($p) => strtolower($p)) if you have any risk of casing drift between role definitions and tokenCan checks — it's a cheap guard against a confusing class of bug.

Teams: gate the whole app on Jetstream::hasTeamFeatures(). Don't sprinkle if (config(...)) around; use the facade:

if (Jetstream::hasTeamFeatures()) {
    // $user->currentTeam, ->personalTeam, ->allTeams(),
    // ->switchTeam($team), ->teamRole($team), ->ownsTeam($team)
}

The Laravel\Jetstream\HasTeams trait supplies all of that. current_team_id is what most of your authorization should key off, and team-scoped routes should sit behind auth:sanctum + your own team-membership middleware, not just auth.

API tokens: Sanctum-backed, only available when Features::api() is enabled. Issue and check with $user->createToken('name', ['read']) and $request->user()->tokenCan('read'). Protect API routes with auth:sanctum — a plain auth guard will silently accept session auth and confuse your token tests.

Profile photos: HasProfilePhoto gives you profilePhotoUrl, updateProfilePhoto, deleteProfilePhoto. Point profile_photo_disk at a public disk and make sure php artisan storage:link ran (the installer does it, but container rebuilds lose the symlink). For private disks you'll need to override profilePhotoUrl to return a temporary URL.

Stack-specific extension points:

Livewire stack Inertia stack
Layout resources/views/layouts/app.blade.php resources/js/Layouts/AppLayout.vue
Screens class-based Livewire components + resources/views/livewire resources/js/Pages/**
Nav Blade x-nav-link JetstreamNavLink / slot props
Shared data Blade props ShareInertiaData → $page.props

For Inertia, remember shared props are camel-cased and namespaced: $page.props.auth.user, $page.props.jetstream.hasTeamFeatures, $page.props.jetstream.canManageApiTokens.

Testing: Jetstream scaffolds Pest 2 (v3.1.0+) or PHPUnit feature tests for registration, password reset, 2FA, teams, and API tokens. Keep them — they're your regression net when you swap actions. Feature-conditional tests are skipped when the feature is off, so php artisan test stays green in trimmed-down installs. In your own tests, RefreshDatabase + $this->actingAs($user) is the pattern; for team-scoped assertions set $user->current_team_id explicitly rather than relying on login-time defaults.

Gotchas and Tips

  • The installer copies Blade views into your app (v3.x). loadViewsFrom was removed in 3.0.1, so resources/views/vendor/jetstream overrides no longer work — the files are simply yours to edit. Consequence: package upgrades won't bring view fixes. Re-running the installer with --force will overwrite your edits; diff first.
  • <x-jet-input> is dead. The "Jet" component prefix was removed in 2.12.0 — it's <x-input>, <x-button>, <x-dialog-modal>. Every tutorial written before 2022 uses the old names.
  • $page.user → $page.auth.user in Inertia as of 3.0.0. Combined with the userPage → usePage typo fix in 3.1.0, most copy-pasted Inertia snippets from blogs are broken on a current install.
  • Enabling teams after the fact is not just a config flip. You need the teams, team_user, and team_invitations tables plus current_team_id on users. Publish and re-run migrations (--tag=jetstream-migrations) rather than assuming Features::teams() is enough; a missing column surfaces as a null currentTeam and authorization that passes when it shouldn't.
  • Jetstream::ignoreMigrations() must be called in register(), before the package's migration paths are loaded. Put it in boot() and it silently does nothing.
  • Email verification requires you to opt in at the model level. Uncomment implements MustVerifyEmail on App\Models\User and enable the Fortify feature. Only one of the two, and the verified middleware either 403s everyone or lets everyone through.
  • 2FA is gated behind password confirmation. If password.confirm is in the middleware group, 2FA setup appears broken until you've confirmed within password_timeout. The refresh-on-two-factor-challenge bug was fixed in 3.1.1 — pin at least that if you see the challenge page looping.
  • Inertia stack needs Ziggy. SSR usage of route() inside setup() is a known historical foot-gun (fixed 2.8.5); prefer the usePage().props route helpers or route() inside render, and make sure @routes is present in your root Blade.
  • Config is read at boot. After toggling any feature, run php artisan config:clear (or config:cache in prod). A stale cached config is the #1 cause of "the feature is enabled but the UI is missing".
  • Dark mode (3.0.0) needs Tailwind cooperation. darkMode: 'class' in tailwind.config.js plus the dark: variants. Upgrading from 2.x gives you the toggle without the styles — plan a Tailwind pass, not just a composer bump.
  • Deleting a user is more than $user->delete(). The DeleteUser action handles team cleanup and personal access tokens; if you own users with teams, decide the semantics explicitly. Also note the logout redirect after deletion follows the Fortify-configured redirect (2.13.0).
  • Livewire component names are strings. @livewire('profile.update-profile-information-form') breaks silently-ish if you relocate a view. Keep the namespace mapping in mind before renaming files.
  • Composer/NPM metadata is misleading here. "Dependents: 0" reflects that Jetstream is installed as a scaffold, not required by libraries — it says nothing about adoption. Likewise, a 4k-star repo with a stale README is a maintenance signal, not a quality signal: read the CHANGELOG before any upgrade, since this package ships behavioural changes (permission casing, view loading, prop names) in patch-level releases.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
vento/laravel-airbrake
wfeller/laravel-batch
maco-studios/mage-os-installer
busarm/armie
siberfx/laravel-logger
kfteam1991/dcat-admin
dashed/dashed-laposta
dashed/dashed-ecommerce-montaportal
dashed/dashed-ecommerce-etsy
neohq/string-blade-compiler
log1x/acf-composer
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core
nodisrupt/laravel-agent
sierratecnologia/media-manager