You get a bonus - 1 coin for daily activity. Now you have 1 coin

Pipeline Architecture: Concept, Examples, Pros and Cons

Lecture



Pipeline architecture — is a way of building a program in which data passes through a chain of independent handlers.

It is often called:

  • Pipeline architecture
  • Pipe and Filter architecture
  • Conveyor
  • Filter chain

The main idea:

Input data → step 1 → step 2 → step 3 → result

Each step performs one specific operation and passes the result on.

Pipeline Architecture: Concept, Examples, Pros and Cons

1. A simple analogy

Imagine a factory assembly line:

Raw materials → Cleaning → Processing → Quality check → Packaging

Programming uses a similar scheme:

Raw data → Cleaning → Transformation → Validation → Saving

For example, importing users from a CSV:

CSV file
   ↓
Read the file
   ↓
Parse the CSV
   ↓
Trim whitespace
   ↓
Normalize email
   ↓
Check required fields
   ↓
Save to the database

2. Core elements

This architecture usually distinguishes several roles.

Producer

Creates or obtains data.

Examples:

- reads a file
- accepts an HTTP request
- receives a message from a queue
- reads data from a database
- fetches data from an external API

Example:

ReadCsvFile

Transformer

Modifies the data.

Examples:

- trimming strings
- converting email to lowercase
- converting JSON into an array
- normalizing a phone number
- adding a computed field

Example:

NormalizeEmail

Tester / validating filter

Checks the data and decides whether it passes further or not.

Examples:

- is the email valid?
- is the name field filled in?
- is age greater than 18?
- is the record not a duplicate?

Example:

ValidateEmail

Consumer

Receives the final result and does something with it.

Examples:

- saves to a database
- sends an email
- writes a log
- sends data to a queue
- returns an HTTP response

Example:

SaveToDatabase

3. General scheme of the pipeline architecture

Pipeline Architecture: Concept, Examples, Pros and Cons

But this is not a hard rule.

You can have many transformers:

Producer → Transformer → Transformer → Transformer → Consumer

You can have many checks:

Producer → Tester → Tester → Tester → Consumer

You can even build a pipeline out of the middle alone:

Normalize → Validate → Format

An example of a case with several Producers — sometimes a pipeline gathers data from several sources:

Pipeline Architecture: Concept, Examples, Pros and Cons

But this is no longer a simple linear pipeline — it is a branching pipeline / pipeline graph.

An example of a case with several Consumers. For instance, after processing the data you can:

Pipeline Architecture: Concept, Examples, Pros and Cons

Sequentially or in parallel

4.1 PHP example

Suppose we have an array of users:

$users = [
    ['name' => ' Ivan ', 'email' => ' IVAN@EXAMPLE.COM '],
    ['name' => '', 'email' => 'wrong-email'],
    ['name' => ' Anna ', 'email' => ' ANNA@EXAMPLE.COM '],
];

Let's create several filters.

interface PipelineStep
{
    public function handle(array $items): array;
}

Filter 1: trimming whitespace

class TrimFields implements PipelineStep
{
    public function handle(array $items): array
    {
        return array_map(function ($item) {
            $item['name'] = trim($item['name']);
            $item['email'] = trim($item['email']);

            return $item;
        }, $items);
    }
}

Filter 2: email normalization

class NormalizeEmail implements PipelineStep
{
    public function handle(array $items): array
    {
        return array_map(function ($item) {
            $item['email'] = strtolower($item['email']);

            return $item;
        }, $items);
    }
}

Filter 3: data validation

class ValidateUsers implements PipelineStep
{
    public function handle(array $items): array
    {
        return array_filter($items, function ($item) {
            return $item['name'] !== ''
                && filter_var($item['email'], FILTER_VALIDATE_EMAIL);
        });
    }
}

The pipeline runner

class Pipeline
{
    private array $steps;

    public function __construct(array $steps)
    {
        $this->steps = $steps;
    }

    public function run(array $input): array
    {
        $data = $input;

        foreach ($this->steps as $step) {
            $data = $step->handle($data);
        }

        return $data;
    }
}

Usage

$pipeline = new Pipeline([
    new TrimFields(),
    new NormalizeEmail(),
    new ValidateUsers(),
]);

$result = $pipeline->run($users);

print_r($result);

The result will look roughly like this:

[
    ['name' => 'Ivan', 'email' => 'ivan@example.com'],
    ['name' => 'Anna', 'email' => 'anna@example.com'],
]

The user with an empty name and an invalid email was filtered out.

4.2 JavaScript example

const producer = () => [1, 2, 3, 4, 5];

const transformer = (items) => items.map(x => x * 2);

const tester = (items) => items.filter(x => x > 5);

const consumer = (items) => {
  console.log(items);
};

const data = producer();
const transformed = transformer(data);
const tested = tester(transformed);
consumer(tested);

Result:

[6, 8, 10]

So the flow looks like this:

Producer → Transformer → Tester → Consumer

5. Example using a config

A pipeline can be described not only in code, but also through configuration.

For example:

pipeline:
  - TrimFields
  - NormalizeEmail
  - ValidateUsers
  - SaveUsersToDatabase

And the code will read the config and run the required classes.

This approach is convenient when you often need to change the order of the steps without modifying the main code.

6. Error handling

In a pipeline architecture, errors can be handled in different ways.

Option 1: stop the entire pipeline

ReadFile → ParseCsv → Normalize → Save
              ↑
             error

If the CSV is corrupted, there is no point in going further.

try {
    $result = $pipeline->run($input);
} catch (Throwable $e) {
    echo "Pipeline failed: " . $e->getMessage();
}

Fail fast

Sometimes a pipeline should fail immediately.

For example:

- a required config is missing
- an invalid API key
- no database connection
- the structure of the input data is broken

This is called fail fast.

That is, the system does not try to «somehow carry on», but reports right away:

Pipeline cannot continue

Option 2: skip the faulty item

For example, one CSV row is bad but the rest are fine.

1000 rows → 980 processed → 20 errors saved to a report

Option 3: send the error to a separate stream

Valid data   → SaveToDatabase
Invalid data → ErrorReport

This approach is often used in imports, ETL and queues.

Option 4: retry

If the error is temporary:

  • - the API is unavailable
  • - the network timed out
  • - the database is temporarily overloaded

you can try repeating the step several times.

Option 5: use a Dead Letter Queue

In queue-based systems such as RabbitMQ, Kafka or AWS SQS, faulty messages are often sent to a Dead Letter Queue.

That is, the message is not deleted forever but moved to a special error queue.

This is needed so that later you can:

  • - look into the cause of the error
  • - fix the data
  • - re-run the processing
  • - find the bug in the code

General recommendations for catching errors when using this architecture in real projects

In real-world architectures, an error-handling strategy is often defined for each step.

For example:

pipeline:
  - step: CsvParser
    on_error: stop

  - step: UserNormalizer
    on_error: skip_item

  - step: EmailValidator
    on_error: send_to_error_channel

  - step: DatabaseSaver
    on_error: retry_then_stop

That is:

CsvParser failed → stop the pipeline
UserNormalizer failed on one row → skip the row
EmailValidator found an error → send it to the error list
DatabaseSaver failed → retry 3 times, then stop

In a pipeline architecture, error handling is usually built around one of these options:

1. Stop the entire pipeline
2. Skip the faulty item
3. Send the error to a separate error channel
4. Retry the step several times
5. Send the message to a Dead Letter Queue
6. Return a Result object instead of an exception
7. Handle the error centrally in the PipelineRunner

The most practical option:

Critical errors → stop the pipeline.
Errors in individual records → send to the error channel.
Temporary errors → retry.
Unrecoverable messages → dead letter queue.

In other words, the pipeline architecture does not require a single universal approach. It usually defines an error-handling policy for each filter in advance.

7. Where the pipeline architecture is used

It comes up very often.

  • 1. HTTP middleware processing
  • 2. CSV / Excel import
  • 3. ETL processes
  • 4. CI/CD pipelines
  • 5. Log processing
  • 6. Compilers
  • 7. Image processing
  • 8. Message queues
  • 9. Event processing
  • 10. Data processing / Big Data

Example: HTTP middleware

In Laravel, Express.js, Symfony and other frameworks, a request passes through a chain of middleware:

Request
   ↓
CheckMaintenanceMode
   ↓
StartSession
   ↓
Authenticate
   ↓
CheckPermissions
   ↓
Controller
   ↓
Response

This also resembles a pipeline.

Example: CI/CD

Commit
   ↓
Install dependencies
   ↓
Run tests
   ↓
Build application
   ↓
Deploy

Each step receives the result of the previous one and either continues execution or halts the process.

Example: image processing

Original image
   ↓
Resize
   ↓
Compress
   ↓
Add watermark
   ↓
Save

8. Advantages of the pipeline architecture

1. Easy to understand

Each step is responsible for a single task.

  • NormalizeEmail is responsible only for the email.
  • ValidateUser is responsible only for validation.
  • SaveUser is responsible only for saving.

2. Easy testing

Each filter can be tested separately.

  • We test TrimFields separately
  • We test ValidateEmail separately
  • We test SaveToDatabase separately

3. Flexibility

You can easily add a new step:

NormalizePhone

And get:

TrimFields → NormalizeEmail → NormalizePhone → ValidateUsers

4. Reuse

A single filter can be used in different pipelines.

For example:

NormalizeEmail

can be used in user registration, in CSV import, and in profile updates.

5. Convenient configuration

You can change the order of the steps through a config:

pipeline:
  - TrimFields
  - NormalizeEmail
  - ValidateUsers

9. Drawbacks of the pipeline architecture

1. Hard to trace the data flow

If there are a great many steps, it is difficult to tell exactly where the data changed.

Step1 → Step2 → Step3 → Step4 → Step5 → Step6 → Step7...

Solution:

  • - log the input/output of important steps
  • - give filters meaningful names
  • - do not make pipelines too long

2. Overhead

If every step creates new objects or copies large arrays, performance may degrade.

3. Not always suitable for complex business logic

If the logic branches heavily:

if A → B → C
if D → E → F
if G → H → I

then a simple linear pipeline can become awkward.

In that case it is better to use:

- workflow engine
- state machine
- event-driven architecture
- orchestration service

4. The danger of overly granular filters

If you create too many tiny steps, the code can become fragmented.

Bad:

  • TrimName
  • TrimEmail
  • TrimPhone
  • LowercaseEmail
  • RemoveSpacesFromPhone
  • ValidateName
  • ValidateEmail
  • ValidatePhone

Sometimes it is better to merge closely related operations:

  • NormalizeUserFields
  • ValidateUserFields

10. Pipeline architecture and Chain of Responsibility

The pipeline architecture resembles Chain of Responsibility, but there is a difference.

Pipeline

Each step usually processes the data and passes it on.

A → B → C → D

Chain of Responsibility

Each handler can decide whether to handle the request or pass it on.

A did not handle it → B did not handle it → C handled it → stop

Chain of Responsibility example:

Support Level 1 → Support Level 2 → Support Level 3

Pipeline example:

Parse → Normalize → Validate → Save

11. When to use the pipeline architecture

The pipeline architecture is a good fit when:

  • - there is sequential data processing;
  • - the steps can be isolated from one another;
  • - the order of the steps matters;
  • - stages need to be added/removed easily;
  • - stages need to be tested separately;
  • - the data passes through a clear chain.

Examples of well-suited tasks:

  • - importing users from a CSV;
  • - order processing;
  • - form validation;
  • - report preparation;
  • - image processing;
  • - the CI/CD process;
  • - log filtering.

12. When not to use the pipeline architecture

It is better not to use a simple pipeline if:

  • - the logic is too chaotic;
  • - there are many cyclic transitions;
  • - each step depends heavily on the internal details of another step;
  • - the data constantly has to go back;
  • - the process looks more like a complex state graph.

For example, for a complex order lifecycle it may be better to use:

State Machine

And for interaction between many services:

Saga / Orchestration / Event-driven architecture

13. A short Laravel example

Laravel has a built-in Pipeline.

The idea is roughly this:

use Illuminate\Pipeline\Pipeline;

$result = app(Pipeline::class)
    ->send($userData)
    ->through([
        TrimFields::class,
        NormalizeEmail::class,
        ValidateUser::class,
    ])
    ->thenReturn();

Each class can have a handle method:

class NormalizeEmail
{
    public function handle(array $data, Closure $next)
    {
        $data['email'] = strtolower(trim($data['email']));

        return $next($data);
    }
}

This is a ready-made example of the pipeline approach in a real framework.

14. Conclusions

Pipeline architecture — is an approach in which data passes through a sequence of independent steps.

Data source → processing → validation → result

The most important points:

  • 1. Each filter performs one clear task.
  • 2. Filters can be combined.
  • 3. Filters of the same kind can be placed one after another.
  • 4. Producer and Consumer do not always have to be separate classes.
  • 5. Errors can be stopped, skipped, logged or sent to a separate stream.
  • 6. The order of the steps is determined by the data format and the business logic.

Very briefly:

Pipeline = data travels along a chain of handlers.
Each handler does something and passes the result on.

Comments

To leave a comment

If you have any suggestion, idea, thanks or comment, feel free to write. We really value feedback and are glad to hear your opinion.
To reply

Lectures and tutorial on "Software and information systems development"

Terms: Software and information systems development