Composable, traceable and declarative Flow Pipelines for Laravel. A modern alternative to Laravel's Pipeline, with support for conditional steps, nested flows, tracing, validation, and more.
- Overview
- β¨ Features
- π¦ Installation
- π Quick Start
- π‘οΈ Error Handling
- π Step Groups & Nested Flows
- π YAML Flow Definitions
- βοΈ Configuration
- π Documentation
- π‘ Examples
- π§ͺ Testing
- π§ Requirements
- π Performance
- π€ Contributing
- π Security
- π License
Laravel Flowpipe is a powerful, modern alternative to Laravel's built-in Pipeline package that provides composable, traceable, and declarative flow pipelines. Perfect for building complex business workflows, data processing pipelines, and API integrations with advanced error handling and retry mechanisms.
- π Fluent API - Chainable, expressive syntax for building pipelines
- π Flexible Steps - Support for closures, classes, and custom steps
- π― Conditional Logic - Built-in conditional step execution
- π Tracing & Debugging - Track execution flow and performance
- π‘οΈ Error Handling - Comprehensive retry, fallback, and compensation strategies
- οΏ½ Step Groups - Reusable, named collections of steps
- π― Nested Flows - Create isolated sub-workflows
- π YAML Support - Define flows in YAML for easy configuration
- π§ͺ Test-Friendly - Built-in test tracer for easy testing
- β‘ Performance - Optimized for speed and memory efficiency
- π¨ Artisan Commands - Full CLI support for flow management
- β Flow Validation - Validate flow definitions with error reporting
Install the package via Composer:
composer require grazulex/laravel-flowpipe
π‘ Auto-Discovery
The service provider will be automatically registered thanks to Laravel's package auto-discovery.
Publish configuration:
php artisan vendor:publish --tag=flowpipe-config
use Grazulex\LaravelFlowpipe\Flowpipe;
$result = Flowpipe::make()
->send('Hello World')
->through([
fn($data, $next) => $next(strtoupper($data)),
fn($data, $next) => $next(str_replace(' ', '-', $data)),
fn($data, $next) => $next($data . '!'),
])
->thenReturn();
// Result: "HELLO-WORLD!"
use Grazulex\LaravelFlowpipe\Flowpipe;
// Create with debug tracing
$debugFlow = Flowpipe::debug(true, 'flowpipe');
$result = $debugFlow
->send($data)
->through($steps)
->thenReturn();
// Create with performance tracing
$perfFlow = Flowpipe::performance();
$result = $perfFlow
->send($data)
->through($steps)
->thenReturn();
// Create with test tracing (for unit tests)
$testFlow = Flowpipe::test();
$result = $testFlow
->send($data)
->through($steps)
->thenReturn();
// Define reusable step groups
Flowpipe::group('text-processing', [
fn($data, $next) => $next(trim($data)),
fn($data, $next) => $next(strtoupper($data)),
fn($data, $next) => $next(str_replace(' ', '-', $data)),
]);
// Use groups in flows
$result = Flowpipe::make()
->send(' hello world ')
->useGroup('text-processing')
->through([
fn($data, $next) => $next($data . '!'),
])
->thenReturn();
// Result: "HELLO-WORLD!"
// Exponential backoff retry
$result = Flowpipe::make()
->send(['api_url' => 'https://api.example.com/data'])
->exponentialBackoff(3, 100, 2.0) // 3 attempts, 100ms base delay, 2x multiplier
->through([
fn($data, $next) => $next(callExternalAPI($data['api_url'])),
fn($data, $next) => $next(processAPIResponse($data)),
])
->thenReturn();
Laravel Flowpipe provides comprehensive error handling strategies:
// Exponential backoff retry
$result = Flowpipe::make()
->send($userData)
->exponentialBackoff(3, 100, 2.0) // 3 attempts, 100ms base delay, 2x multiplier
->through([
fn($data, $next) => $next(saveToDatabase($data)),
])
->thenReturn();
// Simple fallback with default value
$result = Flowpipe::make()
->send(['user_id' => 123])
->withFallback(fn($payload, $error) => ['cached_data' => true])
->through([
fn($data, $next) => $next(fetchUserProfile($data['user_id'])),
])
->thenReturn();
Laravel Flowpipe supports reusable step groups and nested flows for better organization:
Define reusable groups of steps:
// Define reusable step groups
Flowpipe::group('user-validation', [
fn($user, $next) => $next(filter_var($user['email'], FILTER_VALIDATE_EMAIL) ? $user : throw new InvalidArgumentException('Invalid email')),
fn($user, $next) => $next(strlen($user['name']) > 0 ? $user : throw new InvalidArgumentException('Name required')),
]);
Flowpipe::group('notifications', [
fn($user, $next) => $next(array_merge($user, ['email_sent' => true])),
fn($user, $next) => $next(array_merge($user, ['logged' => true])),
]);
// Use groups in flows
$result = Flowpipe::make()
->send(['email' => '[email protected]', 'name' => 'John Doe'])
->useGroup('user-validation')
->useGroup('notifications')
->thenReturn();
Create isolated sub-workflows:
$result = Flowpipe::make()
->send('hello world')
->nested([
// This nested flow runs independently
fn($data, $next) => $next(strtoupper($data)),
fn($data, $next) => $next(str_replace(' ', '-', $data)),
])
->through([
// Main flow continues with nested result
fn($data, $next) => $next($data . '!'),
])
->thenReturn();
// Result: "HELLO-WORLD!"
Create flow definitions in YAML for easy configuration:
# flow_definitions/user_processing.yaml
flow: UserProcessingFlow
description: Process user data with validation
send:
name: "John Doe"
email: "[email protected]"
steps:
- type: group
name: user-validation
- type: nested
steps:
- type: closure
action: uppercase
- type: group
name: notifications
# Run flows via Artisan commands
php artisan flowpipe:run user_processing
php artisan flowpipe:export user_processing --format=mermaid
$result = Flowpipe::make()
->send(' hello world ')
->through([
fn($text, $next) => $next(trim($text)),
fn($text, $next) => $next(ucwords($text)),
fn($text, $next) => $next(str_replace(' ', '-', $text)),
])
->thenReturn();
// Result: "Hello-World"
use App\Flowpipe\Steps\ValidateUserStep;
use App\Flowpipe\Steps\SendWelcomeEmailStep;
$user = Flowpipe::make()
->send($userData)
->through([
new ValidateUserStep(),
new SendWelcomeEmailStep(),
])
->thenReturn();
Check out the examples directory for more examples.
Laravel Flowpipe includes a test tracer for easy testing:
use Grazulex\LaravelFlowpipe\Tracer\TestTracer;
public function test_user_processing_flow()
{
$result = Flowpipe::test()
->send(['name' => 'John'])
->through([
fn($data, $next) => $next(strtoupper($data['name'])),
])
->thenReturn();
$this->assertEquals('JOHN', $result);
}
For detailed documentation, examples, and advanced usage:
- π Full Documentation
- π― Examples
- π§ Configuration
- π§ͺ Testing
- π‘οΈ Error Handling
- PHP: ^8.3
- Laravel: ^12.0
- Carbon: ^3.10
- Symfony YAML: ^7.3
We welcome contributions! Please see our Contributing Guide for details.
If you discover a security vulnerability, please review our Security Policy before disclosing it.
Laravel Flowpipe is open-sourced software licensed under the MIT license.
Made with β€οΈ for the Laravel community
- CODE_OF_CONDUCT.md - Our code of conduct
- CONTRIBUTING.md - How to contribute
- SECURITY.md - Security policy
- RELEASES.md - Release notes and changelog