Binding — registering a class or closure in a container
Definition
Binding is the act of registering an instruction with a dependency injection container that tells it how to construct a type. A binding maps an abstract identifier (an interface name, a class name, or a string key) to a concrete factory: either a concrete class name, a closure, or an existing instance. The binding itself does not create anything — it is a recipe stored in the container until resolution is requested.
In Practice
<?php
// 1. Transient binding: a new instance is created on every resolution
app()->bind(Mailer::class, SmtpMailer::class);
// 2. Singleton binding: the same instance is returned on every resolution
app()->singleton(Cache::class, RedisCache::class);
// 3. Closure binding: full control over construction
app()->bind(PaymentGateway::class, function ($app) {
return new StripeGateway(
apiKey: config('services.stripe.key'),
logger: $app->make(LoggerInterface::class),
);
});
// 4. Instance binding: bind a pre-built object (always singleton behaviour)
$logger = new FileLogger('/var/log/app.log');
app()->instance(LoggerInterface::class, $logger);
// 5. Contextual binding: different concrete classes for different consumers
app()->when(UserController::class)
->needs(Repository::class)
->give(EloquentUserRepository::class);
app()->when(AdminController::class)
->needs(Repository::class)
->give(EloquentAdminRepository::class);
// Bindings are typically registered in a ServiceProvider:
class AppServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->app->singleton(PaymentGateway::class, function ($app) {
return new StripeGateway(config('services.stripe.key'));
});
}
}In Laravel, bindings are registered in service providers during the register() phase of the application bootstrap. The register() method must only register bindings — it must not call other services because the container may not yet have built them. The boot() method runs after all providers have registered and is safe for inter-service dependencies.
In Context
Interviewers ask about binding to confirm you understand the difference between bind() and singleton() and when each is appropriate. A transient binding (plain bind) gives each consumer its own instance — useful for objects with state that should not be shared (e.g., a query builder). A singleton binding is appropriate for stateless services (loggers, cache clients, mailers) where constructing multiple copies wastes resources.
A common mistake is registering bindings inside boot() instead of register(). While this often works, it creates an implicit dependency on boot order and can cause resolution failures when a provider's boot() method tries to resolve something that hasn't been bound yet.
Related terms: "resolution" is the consumer-side act of asking the container for a type; "binding" is the producer-side act of teaching the container how to build it. "Service provider" is Laravel's mechanism for organizing bindings into cohesive units.