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

Laravel Stubs Laravel Package

juststeveking/laravel-stubs

Laravel Stubs provides publishable stub files for Laravel's make commands, letting you customize generated classes, controllers, models, and other scaffolding to match your project's conventions without editing vendor files.

View on GitHub
Deep Wiki
Context7

Getting Started

The mental model to hold onto: this package is a delivery mechanism for files, not a runtime feature. Laravel's make:* commands already check base_path('stubs/{name}.stub') before falling back to the framework's bundled template. This package ships an opinionated set of those .stub files. Publish them and you are done — the framework does the rest.

  1. Install as a dev dependency.

    composer require --dev juststeveking/laravel-stubs
    
  2. Publish the stubs into the project root. Use the package's publish command (or Laravel's built-in php artisan stub:publish if the package relies on it) so files land in stubs/ at the project root:

    php artisan vendor:publish --tag=stubs
    # or
    php artisan stub:publish
    
  3. Verify what actually got published. Do not assume. List the directory and compare against the stub names Laravel's make commands expect for your Laravel major:

    ls stubs/
    
  4. First use case — read before you generate. Generate one representative artifact and read it end to end:

    php artisan make:model Invoice -mf
    php artisan make:controller InvoiceController --resource
    php artisan make:request StoreInvoiceRequest
    php artisan make:test InvoiceTest
    

    Open the generated files. You are looking for declare(strict_types=1), final on classes, typed properties, promoted constructors, and — critically — that {{ namespace }}, {{ class }}, {{ rootNamespace }} were all substituted, not left as literal text.

  5. Decide now: keep the dependency or vendor the files. Once published, the composer package does nothing for make:* output. Everything downstream is driven by stubs/ in your repo. Most teams should commit stubs/, drop the requirement, and treat the templates as first-class source.

Implementation Patterns

Partial override. You do not need to override every stub. Delete the ones you don't care about; a missing file means the framework default is used. A minimal, high-value set is typically: model.stub, controller.stub, controller.plain.stub, request.stub, policy.stub, job.stub, test.stub, migration.create.stub, migration.stub. Fewer files means less to audit on every Laravel upgrade.

Edit literals, preserve tokens. The correct change is always to surrounding text — never to the placeholder names. Adding declare(strict_types=1);, changing class {{ class }} to final class {{ class }}, adding a promoted constructor — all safe. Renaming {{ class }} to {{ modelClass }} silently breaks generation (see Gotchas).

Namespace-aware stubs for non-App\ code. In composer.json you can register additional namespaces for domain code; the stubs' {{ namespace }} token resolves per-command, so the same model.stub works for both App\Models\ and Domain\Billing\Models\. Do not hardcode App\ anywhere — check each published stub for it and replace with {{ rootNamespace }} or {{ namespace }}.

Golden-file tests. The single most valuable habit with stubs: a small test suite that generates artifacts into a temp directory and asserts on the output. Pest/PHPUnit both work:

it('generates a compliant model', function () {
    $this->artisan('make:model', ['name' => 'FakeInvoice', '--factory' => true]);
    $contents = File::get(app_path('Models/FakeInvoice.php'));
    expect($contents)
        ->toContain('declare(strict_types=1);')
        ->toContain('final class FakeInvoice')
        ->not->toContain('{{');
    File::delete(app_path('Models/FakeInvoice.php'));
});

This converts the silent-failure mode (see Gotchas) into a loud one. Run it in CI on every PR that touches stubs/.

Lint-and-analyse the output, not just the stubs. Add a CI step that generates one artifact per stub type and runs Pint + PHPStan/Larastan over the results. Generated code that fails your own ruleset is a stub bug, and this catches it at PR time rather than weeks later in review.

Pair with your formatter. Run vendor/bin/pint --dirty after generation during local development so hand-edited stubs quickly reveal formatting drift. If Pint always rewrites your stub output, the stub is fighting the ruleset — fix the stub, not the formatter.

Local make command wrapping. If you have a house php artisan make:domain-model, have it read base_path('stubs/model.stub') directly rather than bundling its own templates. One source of truth for scaffolding.

Review the stub diff like a design doc. A PR that changes stubs/model.stub affects every model generated from that day forward. It deserves a reviewer from whoever owns the code standard, and it deserves a note in CONTRIBUTING.md about why the stub differs from stock Laravel.

Gotchas and Tips

The failure mode is silent. If stubs/model.stub is misspelled, or the filename doesn't match what your Laravel version's make:model looks for, the framework default is used with no error, no warning, no log line. Your generated code just quietly stops matching the standard. After publishing, and again after every Laravel major upgrade, generate one artifact per stub type and grep for declare(strict_types=1) (or whatever your marker is). This is a ten-minute recurring job that prevents a year of drift.

Stub filenames change between Laravel majors. test.stub vs. pest-flavoured stubs, controller.plain.stub, migration.create.stub vs. migration.stub — the expected names track the framework skeleton, not the package. Add "re-verify vendored stubs against the new skeleton" to your upgrade checklist. Do not assume a package release exists for the new major; check the tags.

--force on publish overwrites your edits. Commit stubs/ before re-publishing anything, and read the diff. Equally, publishing without --force leaves existing files untouched — so a half-populated stubs/ directory can look complete while half the stubs are still framework defaults.

Not every command supplies every token. {{ factory }}, {{ migration }}, {{ modelVariable }}, {{ factoryNamespace }} are injected by specific make commands. If you use a token in a stub whose command doesn't provide it, you get the literal {{ token }} in the generated file. Generate once per stub after any edit and grep for {{.

final and readonly have downstream costs. final class blocks Mockery partial mocks; readonly promoted properties conflict with Eloquent's mass-assignment and hydration. Apply final where it's cheap (controllers, requests, policies, jobs) and be deliberate in the model stub — especially if your test suite mocks models.

declare(strict_types=1) in generated code can surface latent type-juggling. Usually a win, occasionally a surprise in a controller that passed "5" where an int was expected. Cheap to fix when generated, expensive to fix in twenty hand-written files — another argument for greenfield-only adoption.

Keep stubs/ out of autoload and static analysis. It contains .stub extensions so Composer won't autoload it, but check phpstan.neon excludePaths and any pint.json exclude if the files ever get renamed to .php by tooling.

Second stub-publishing package in the same repo is a trap. Stub resolution order and publish conflicts produce "why did my model generate wrong" bugs that are genuinely slow to diagnose. One owner for stubs/, one package (ideally zero, once vendored).

Extension points are the files themselves. There is no config file to tune, no service provider behaviour to override that matters day-to-day. The extension point is: open stubs/foo.stub, edit it, generate, diff. If you find yourself wanting a config knob, you want a custom make command instead.

Check the licence before vendoring. Copying the stub files into your repo is the recommended end state; make sure the licence permits it, and keep an attribution note in stubs/README.md along with a line explaining how your stubs differ from stock Laravel — otherwise a new hire will copy a tutorial pattern and undo the standard in one commit.

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.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib