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 Auto Binder Laravel Package

michael-rubel/laravel-auto-binder

Laravel Auto Binder automatically registers interface-to-implementation bindings in the service container using naming conventions, so you can drop manual $bindings entries. Point it at your directories and it wires your classes for cleaner, convention-driven dependency injection.

View on GitHub
Deep Wiki
Context7

Getting Started

The package is a convention-over-configuration container helper: instead of writing a dozen $this->app->bind(FooInterface::class, Foo::class) lines in a service provider, you declare a namespace pair (or naming rule) once and let the package register the bindings during boot.

composer require michael-rubel/laravel-auto-binder
php artisan vendor:publish --tag=config

As of 6.0.0 the package supports Laravel 11 alongside the earlier versions, so the same install works on a current app. The service provider is auto-discovered on Laravel 8+, so there is nothing to add to config/app.php. First place to look is the published config file — it is the entire API surface. In practice it maps an interface namespace to a concrete namespace:

// config/auto-binder.php
return [
    'interfaces' => [
        \App\Contracts\::class => \App\Repositories\::class,
    ],
];

(The exact key names are worth verifying against the published file; the shape is a namespace map, not a per-class list.)

Your first use case is the classic repository pattern:

namespace App\Contracts;

interface UserRepositoryInterface {}

namespace App\Repositories;

class UserRepository implements \App\Contracts\UserRepositoryInterface {}

With those two files in place and the namespace map configured, app(UserRepositoryInterface::class) resolves without a single manual binding. A good first exercise is to add one interface, resolve it in php artisan tinker, and confirm you get the concrete class before converting the rest of your codebase.

Implementation Patterns

Convention-based bulk registration. The value shows up at scale: ten repositories, ten interfaces, ten mappings, zero lines of provider code. Add an interface class and the matching concrete class and the binding exists on the next boot.

Explicit map for legacy namespaces. Most real apps have repositories in App\Repositories, services in App\Services, and third-party implementations elsewhere. Keep one namespace pair per logical layer rather than one giant scan root, so the matching stays predictable.

Singleton vs. transient. Default container bind semantics give you a fresh instance per resolution. If a service is stateless and expensive to construct, register it as a singleton — but see the Octane caveat below before doing so for anything holding request state.

Scoping to modules. For a modular monolith, an entry per module (App\Modules\Billing\Contracts → App\Modules\Billing\Implementations) keeps the auto-binder honest and prevents a module from silently resolving another module's implementation.

Test-time overrides. Auto-binding does not change how you fake dependencies. In a test's setUp, $this->app->bind(UserRepositoryInterface::class, FakeUserRepository::class) still wins because it runs after boot, or use $this->instance(...) for a pre-built mock. Auto-binding is a boot-time default, not a lock.

Integration with feature code. Resolve through the container everywhere — constructor injection in controllers, jobs, and commands — so the auto-binding actually applies. If you new UserRepository() directly anywhere, you have bypassed the mechanism and the abstraction is decorative.

Migration path. Since Laravel 11 the container ships #[Bind] and #[Singleton] attributes, so #[Bind(UserRepository::class)] on the interface does the same job with no extra dependency and no namespace map. The two are now viable alternatives on the same framework version — pick per interface: attributes for one-off contracts, this package for sweeping namespace-wide conventions across an existing codebase.

Gotchas and Tips

6.0.0 is a major bump — check the support matrix. The headline change is Laravel 11 support plus dependency refreshes; there are no documented API changes to the config map. Major version bumps in this package have historically tracked the framework/PHP floor, so verify your composer.json constraints before upgrading, and stay on the 5.x line if you're pinned to an older Laravel. Test on a branch, not straight to main — the release notes do not enumerate breaking changes explicitly.

The maintenance risk is lower than it was. Earlier versions looked frozen, but 6.0.0 shows the package is still receiving updates from its author. That said, it is a small, single-maintainer package with a narrow surface: pin the version, and remember the whole mechanism is replaceable in a provider file if it ever stalls again.

Failures are deferred to runtime. A typo in a namespace or a class that doesn't implement the interface won't blow up at boot — it blows up when something resolves it, which may be a queued job at 2 a.m. Add a cheap smoke test that loops over your contracts and calls app()->make($interface); it catches misconfiguration in one assertion.

Matching can overreach. Namespace-wide scanning is convenient and indiscriminate. An interface with no implementation in the target namespace, or two candidates, produces confusing behaviour. Keep the namespace pairs tight and prefer explicit mappings where naming is ambiguous.

Boot order matters. Bindings registered later overwrite earlier ones. If a package provider registers a binding for the same interface after yours, that package wins — which is usually what you want, but it can also mean your auto-bound implementation is silently shadowed. Register explicit, intentional overrides in a provider that boots last.

Config caching. If the package builds its map from config, php artisan config:cache freezes it; new interface classes then require a config:clear (or a redeploy) before they resolve. If it scans the filesystem at boot instead, you pay a small directory-walk cost on every request — negligible for app/, problematic if a root is pointed at a large vendor tree.

Avoid singleton leakage. A singleton bound this way survives across requests under Octane and across jobs in a queue worker. Anything holding request-scoped state should stay transient.

Don't auto-bind contracts you don't own. Framework and third-party interfaces have their own providers and their own expected implementations. Restrict the map to your App\ namespaces.

Debugging. app()->bound(FooInterface::class) and dd(app()->getBindings()) are the fastest way to see whether the package actually registered anything. If the binding is missing, the config namespace key is almost always the culprit — a missing or extra trailing backslash is a common cause.

Extension point. The service provider's registration loop is the seam: subclass it or publish the config and adjust namespaces rather than editing vendor code, and keep the resulting config in version control so the implicit wiring is at least documented somewhere.

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.
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table
siberfx/flysystem-wasabi
hollyit/token-replace
ippanelcom/laravel-sdk
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel