Introduction
Laravel 11 and 13 no longer ship with routes/api.php by default. When you need a stateless API, you run php artisan install:api — a single command that creates the routes file, installs Laravel Sanctum for token authentication, and wires up the api middleware group.
Key Concepts
php artisan install:api: Scaffolds everything needed to expose a REST API.- Laravel Sanctum: A lightweight API token package that Laravel installs automatically.
auth:sanctummiddleware: Protects API routes by validating the bearer token on each request.bootstrap/app.php->withRouting(): Where the API prefix (/apiby default) is configured.
Real World Context
Most full-stack Laravel apps do not need an API on day one. The install-on-demand approach keeps the starter lean and avoids unused files in projects that only serve Blade pages. The moment you add a mobile app or an SPA, you run install:api and get a production-ready foundation.
Deep Dive
Running the Installer
bashphp artisan install:api
The command:
- Requires
laravel/sanctumvia Composer. - Publishes Sanctum's config and migrations.
- Runs the new migrations (creating a
personal_access_tokenstable). - Creates
routes/api.phpwith a samplemeendpoint. - Updates
bootstrap/app.phpto register the API routes via->withRouting(api: __DIR__.'/../routes/api.php', ...).
The Generated routes/api.php
php<?php use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; Route::get('/user', function (Request $request) { return $request->user(); })->middleware('auth:sanctum');
The auth:sanctum middleware accepts a bearer token in the Authorization header and resolves the matching user. Every route defined in routes/api.php is prefixed with /api automatically.
Issuing a Token
php// In a controller that handles POST /login $user = User::where('email', $request->email)->first(); if (! $user || ! Hash::check($request->password, $user->password)) { throw ValidationException::withMessages([ 'email' => ['The provided credentials are incorrect.'], ]); } return response()->json([ 'token' => $user->createToken('mobile-app')->plainTextToken, ]);
The client stores the token and sends it on subsequent requests as Authorization: Bearer <token>.
Customising the Prefix
Edit bootstrap/app.php:
phpreturn Application::configure(basePath: dirname(__DIR__)) ->withRouting( web: __DIR__.'/../routes/web.php', api: __DIR__.'/../routes/api.php', apiPrefix: 'api/v1', // /api/v1/users instead of /api/users commands: __DIR__.'/../routes/console.php', health: '/up', ) ->create();
Common Pitfalls
- Looking for
routes/api.phpin a fresh project — It does not exist until you runinstall:api. Do not assume old Laravel 10 tutorials still apply. - Forgetting to migrate Sanctum — The installer runs migrations automatically, but if you copy a project without its database, you must re-run
php artisan migrateto create the token table.
Best Practices
- Scope tokens per device — Pass a human-readable name to
createToken('mobile-app')so users can revoke one device without logging out everywhere. - Use abilities — Sanctum supports per-token abilities (
createToken('mobile', ['post:create'])). Prefer granular abilities over wide-open tokens.
Summary
php artisan install:apiis the Laravel 11+/13 way to scaffold an API.- It installs Sanctum and wires up
auth:sanctumfor bearer-token authentication. routes/api.phpis prefixed with/api, customisable viabootstrap/app.php.- Issue tokens with
$user->createToken(name)->plainTextToken.
Code Examples
// First, in your shell:
// php artisan install:api
// Then in routes/api.php:
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
Route::middleware('auth:sanctum')->group(function () {
Route::get('/user', fn (Request $request) => $request->user());
Route::apiResource('posts', PostController::class);
});