Configuration
Tune the spec path, output, suffix, pruning, and depth. Configuration
This guide takes you from a spec file to a working, typed Laravel slice: models, validation, controllers, routes, and a CI gate that keeps them in sync. There are two ways to run the generator: the artisan command inside a Laravel app, and the standalone binary for anything else.
Install the runtime peer and the generator.
The generated classes extend Spatie\LaravelData\Data, so spatie/laravel-data is a runtime
dependency of your app. Without it, a fresh app hits fatal autoload errors as soon as it loads a
generated class. The generator itself is a dev dependency.
composer require spatie/laravel-data:^4.23composer require --dev codewithagents/openapi-laravelGenerate from your spec. One command, full output.
php artisan openapi:generate --spec=openapi.yaml --output=app/DataFor the classic Petstore spec, this is what appears on disk:
app/Data/Pet/PetData.php laravel-data class + spec-derived rules()app/Data/Pet/CategoryData.php per-tag directories mirror the controllersapp/Data/Pet/TagData.phpapp/Data/Pet/ApiResponseData.phpapp/Data/Store/OrderData.phpapp/Data/User/UserData.phpapp/Http/Controllers/Api/AbstractPetController.php one abstract controller per tagapp/Http/Controllers/Api/AbstractStoreController.phpapp/Http/Controllers/Api/AbstractUserController.phproutes/api.generated.php one Route:: entry per operationThe output namespace comes from config/openapi-laravel.php (output.namespace, default
App\Data); set it in the config if you need a different namespace, or override it per run with
--namespace. Set spec and output.path there too and you can then just run:
php artisan openapi:generateWant models only? Pass --no-controllers --no-routes (see the
precedence rules).
Scaffold the concrete controllers, then wire them up.
The generated routes file references concrete controllers (PetController) that extend the
generated abstracts. Scaffold them in one command so the app boots immediately:
php artisan openapi:scaffoldThis writes one stub per controller, each method throwing a LogicException placeholder. The
stubs are yours from that moment: re-running the command (or the generator) never overwrites
them, and the drift gate ignores them. Replace each placeholder with your implementation:
final class PetController extends AbstractPetController{ public function show(int $petId): PetData { return PetData::from(Pet::findOrFail($petId)); }
// ... the abstract class forces you to implement the rest}Then include the generated routes file from routes/api.php:
require base_path('routes/api.generated.php');See the server scaffold guide for the full walkthrough.
Review, commit, and add the drift gate to CI.
The output is deterministic, so commit it like any other code. Then make CI fail whenever the committed files and the spec disagree:
php artisan openapi:check # exit 0 in sync, 1 drift, 2 config errorSee the drift-check guide for a ready-made GitHub Actions job.
Not a Laravel project, or running in a CI step that has no app bootstrapped? The same generator ships as a framework-free binary:
vendor/bin/openapi-laravel --spec=openapi.yaml --output=src/Data --namespace="Acme\\Dto"| Flag | Description |
|---|---|
--spec | Path to your OpenAPI 3.x document (YAML or JSON) |
--output | Directory the generated files are written to |
--namespace | PHP namespace for the generated classes |
--config | Path to a JSON config file (default: ./openapi-laravel.json) |
Controllers and routes are generated by default into <output>/Controllers and
<output>/routes.php; override the locations with --controller-output / --routes-output, or
skip them with --no-controllers / --no-routes. The one-time concrete controller stubs are
available here too:
vendor/bin/openapi-laravel scaffold --spec=openapi.yaml --output=src/DataFor a Customer schema that references a CustomerStatus enum, the generator writes:
app/Data/CustomerData.php laravel-data class with a spec-derived rules() methodapp/Data/CustomerStatus.php native backed enumIf the spec marks fields with readOnly or writeOnly, you also get a write variant such as CustomerWritableData.php. See generated output for full examples.
The default run already scaffolds one Abstract{Tag}Controller per OpenAPI tag and a routes/api.generated.php file, typed by the same Data classes. You extend each abstract controller with your own concrete implementation; php artisan openapi:scaffold writes the initial concrete stubs for you, one time, and regeneration only ever rewrites the Abstract* files. See the server scaffold guide for the full walkthrough, or disable the scaffold with --no-controllers --no-routes (or controllers.enabled / routes.enabled in the config).
Configuration
Tune the spec path, output, suffix, pruning, and depth. Configuration
Generated output
See a full Data class, a backed enum, and the read/write split. Generated output
Server scaffold
Generate abstract controllers and a routes file. Server scaffold