Skip to main content
Version: Laravel: 4.x (current)

Migrating to v4

welcome to Scribe v4.👋 This guide will help you migrate from v3. Not much changed, so you should be done in less than 5 minutes. See the release blog post for the list of new features.


Scribe v4 requires PHP 8 and Laravel 8+. If you're on an older version, you'll need to upgrade.


Upgrade the package version (knuckleswtf/scribe) in your composer.json to ^4.0 and then install:

composer update knuckleswtf/scribe

Automated upgrade

Scribe v4 comes with an upgrade tool that will make the needed changes to your config file and inform you of any manual changes you need to make yourself:

# See what changes will be made:
php artisan scribe:upgrade --dry-run
# Run the upgrade for real
php artisan scribe:upgrade

The tool will back up your old config to config/scribe.php.bak so you can restore it if something wasn't set correctly.


If you use multi-docs, you can run the upgrade command for each of your config files, for instance php artisan scribe:upgrade --config scribe_admin

Config file changes


php artisan scribe:upgrade automatically handles all the changes in this section.

  • A new examples key has been added, to configure how Scribe generates examples. It comes with two keys:
    • faker_seed (the old top-level faker_seed was moved here)
    • models_source, for configuring how Scribe generates example models for API resources and transformers. See the docs for usage.
  • A new groups key has been added. It comes with two items:
    • default (the old default_group was moved here)
    • order, where you can order your groups, subgroups and endpoints. See the docs for usage.

Endpoints sorting


php artisan scribe:upgrade automatically handles all the changes in this section.

In the past, the only way to sort your endpoints was by naming them in alphabetical order (eg "1. Users", "2. Tasks"), or reordering them in the generated YAML files. The first approach makes your documentation ugly, the second isn't very scalable. Scribe v4 brings a simpler approach: list the groups and endpoints in the groups.order config item, in the order you want them in.

Because of this, we've dropped support for the previous editing/renaming files approach, as well as beforeGroup and afterGroup on custom endpoints. Migrating is simple: when you run scribe:upgrade, it will automatically import the existing order of your groups into the groups.order key.

Plugin API

If you've written custom strategies, the class interface has changed a tiny bit.

  • The $routeRules parameter of __invoke() is now optional. This means you should replace array $routeRules with array $routeRules = []

    public function __invoke(
    ExtractedEndpointData $endpointData,
    - array $routeRules
    + array $routeRules = []
    ): ?array
  • There's a new instance property, public ?ExtractedEndpointData $endpointData;. You can add this anywhere in your class. It's not used for anything, and it's not set in the constructor, so you can ignore it, but it's a handy container to set/retrieve the endpoint being processed without having to pass it around.

Blade templates

(For those who published and customized the themes' templates)

No major changes, but three things to note:

  1. Because of the addition of subgroups, we had to make some changes to the groups.blade.php file.
  2. We moved the logic that generates headings for the sidebar.blade.php into a getHeadings method in the HtmlWriter class.
  3. We changed response fields so they can expand/collapse like body parameters. To do this, we:
    • added a nestedResponseFields property to the OutputEndpointData class.
    • renamed body-parameters.blade.php to nested-fields.blad.php, and renamed the parameters input parameter to fields. Here's the commit.

If you're affected by these changes, we recommend you copy the new files from the project's repo, and make any changes you had (they're fairly small files).


To enable PHP 8 attributes, you'll need to manually add the needed strategies to your config file:

'strategies' => [
'metadata' => [
+ Strategies\Metadata\GetFromMetadataAttributes::class,
'urlParameters' => [
+ Strategies\UrlParameters\GetFromUrlParamAttribute::class,
'queryParameters' => [
+ Strategies\QueryParameters\GetFromQueryParamAttribute::class,
'headers' => [
+ Strategies\Headers\GetFromHeaderAttribute::class,
'bodyParameters' => [
+ Strategies\BodyParameters\GetFromBodyParamAttribute::class,
'responses' => [
+ Strategies\Responses\UseResponseAttributes::class,
'responseFields' => [
+ Strategies\ResponseFields\GetFromResponseFieldAttribute::class,

Finally, if you'd like to automatically replace (most of) your docblock tags with attributes (see the docs on annotations for advantages and disadvantages), you can also do that. We've provided a Rector rule to automatically convert certain tags to attributes.