Clean Up Your Laravel Services with Pipelines
Laravel 11
Published 24 February 2025 • Tags: Livewire, Pipelines
As your Laravel app grows, it’s easy for service classes to become bloated and hard to maintain. That’s where service pipelines come in. A pipeline lets you break a process into a sequence of smaller, focused classes that handle just one step. You “pipe” a model, DTO, or array through them—each one makes a change and passes it on.
Think of it like middleware, but for business logic.
A Basic Example
Let’s say you’re registering a new user and want to:
- Validate the data
- Create the user
- Assign a default role
- Send a welcome email
Instead of putting all that into one service, you can do this:
use Illuminate\Pipeline\Pipeline;
$data = [...]; // validated input
$user = app(Pipeline::class)
->send($data)
->through([
\App\Pipelines\CreateUser::class,
\App\Pipelines\AssignDefaultRole::class,
\App\Pipelines\SendWelcomeEmail::class,
])
->thenReturn();
Each class would look like this:
class CreateUser
{
public function handle(array $data, Closure $next)
{
$data['user'] = User::create($data);
return $next($data);
}
}
Why Use Pipelines?
- Cleaner Code: Each step does one thing well. Easier to test and reason about.
- Reusable Steps: You can re-use pipes in different service contexts.
- Extensible: Need to add logging, auditing, or feature flags? Just drop in another class.
- Composable: Great when you want to dynamically build a pipeline, e.g. based on config or user input.
When to Reach for Pipelines
- Complex business logic that involves multiple steps
- Code that’s hard to test because everything is tightly coupled
- You’re already using services and want better structure
- Anywhere you'd otherwise write a large procedural service class
If you’re using the TALL stack, pipelines work beautifully alongside Livewire actions or controller methods, keeping your components slim and focused.
Comments aren't open just yet — but they’re coming soon.
Enjoyed this chapter? Explore more stories