Renaming "Teams" in Laravel Jetstream

While Laravel Jetstream doesn't provide an easy way of renaming the "Team" noun into something like "Project", there is actually a relatively easy way to achieve this. No need to refactor every model or database table if there is a middle road.

Laravel2 / 3Level:

Jetstream is an awesome package; it provides many excellent functionality out of the box. However, for those who are building something that doesn't revolve around teams, they may try to adjust this noun. However, there is no support for doing so at the time of this post.

If you belong to this group and tried to find the answer through Laravel Jetstream's own documentation, specifically the Teams page, then you might have come across the following notice, or warning:

Jetstream's team scaffolding and opinions may not work for every application. If it doesn't work for your use case, feel free to create a non-team based Jetstream application and manually add team functionality to your application based on your own needs.

I couldn't help but detect some sarcasm, maybe this is just me. "If you don't like the team naming convention, then go and build the whole thing yourself." - Hmm, not really helpful. However, maybe there's some middle ground here.

What if we simply decided that we will use the Team naming convention just for our back-end purposes, and for our front-end, we will use a custom noun, like 'Project'. Well, it seems like there is a way to achieve this without renaming all files altogether.

Step 1

Edit your config/jetstream.php and add the following:

'features' => [
        // ... other config
        Features::teams([
            'invitations' => true,
            'noun' => 'project', // ...or something else
        ]),
    ],

To be clear, noun is a custom config rule, but found this the most sensible place to add it.

Step 2

Edit your routes/web.php file and add the following:

use Laravel\Jetstream\Jetstream;
use Laravel\Jetstream\Http\Controllers\CurrentTeamController;
use Laravel\Jetstream\Http\Controllers\Livewire\TeamController;
use Laravel\Jetstream\Http\Controllers\TeamInvitationController;
use Laravel\Jetstream\Http\Controllers\Livewire\UserProfileController;

if (Jetstream::hasTeamFeatures() && $noun = config('jetstream-options.teams.noun', 'team')) {
    Route::get('/'.$noun.'s/create', [TeamController::class, 'create'])->name('teams.create');
    Route::get('/'.$noun.'s/{team}', [TeamController::class, 'show'])->name('teams.show');
    Route::put('/current-'.$noun, [CurrentTeamController::class, 'update'])->name('current-team.update');

    Route::get('/'.$noun.'-invitations/{invitation}', [TeamInvitationController::class, 'accept'])
        ->middleware(['signed'])
        ->name('team-invitations.accept');
}

This will essentially override all of Jetstream's default routing (found in /vendor/laravel/jetstream/routes/livewire.php). By the way, I'm using Livewire here, but I assume this works the same way with Inertia.

By the way, I have maintained the team convention for the route names, saving us from renaming all team route references. Also, this naming would not be visible to the outside world anyway.

Step 3

Now we should rename all Blade files that contain the "Team" label. There are quite a few to inspect, and I don't have any magic trick here. Simply search for things like {{ __('Team or 'team) }} to find most of them. Takes about 5-10 minutes, really.

Notice that I haven't touched other parts of the Team entity (model, database columns, etc.). In fact, I would advice against renaming every bit of "Team" in your Laravel application and only adjust the front-end labeling instead.

On that note, I think having a custom noun is more appropriate than renaming everything. As long as you and your colleagues are aware of the Team naming convention, it will prevent any confusion, especially in regards to Laravel Jetstream's documentation.

In fact, you could make it even more flexible by referring to the `noun' config rule in each of your Blade components (or use View Composers to access it as a variable), so that you only have to define the noun once.

🎁 Bonus

In theory, with this solution users would still be able to visit existing team routes. This is because Laravel jetstream will still register its own routes. While this shouldn't cause any issues, you could resolve this by redirecting traffic using a middleware class, as follows:

class RedirectTeamRoutes
{
    /**
     * Handle the incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return \Illuminate\Http\Response
     */
    public function handle($request, \Closure $next)
    {
        if(str_contains(request()->path(), 'team')){
            $path = str_replace('team', 'project', request()->path());

            return redirect($path);
        }

        return $next($request);
    }
}

Now simply add this middleware class to your /app/Http/Kernel.php inside of the middleware property:

/**
     * The application's global HTTP middleware stack.
     *
     * These middleware are run during every request to your application.
     *
     * @var array
     */
    protected $middleware = [
        \App\Http\Middleware\RedirectTeamRoutes::class,
        // other middleware...
    ];

That should about do it. So far, I haven't noticed a single reference to the "team" entity throughout my application. Although it takes a few steps to adjust this, it's far easier than having rename all files (or wait for a native solution, for that matter).

Good luck and hope to see you around! ✌🏻