Skip to content
intermediate Phase 64 · Extension Strategy

Plugin vs Preference — When to Use Each

Comparing plugins and preferences in Magento 2: when to use plugins vs class preferences, preference limitations, and plugin advantages

45m
1 problems
Topic Progress 0%

What Are Preferences?

Preference Declaration

A preference replaces a class entirely via DI:

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Magento\Catalog\Model\Product"
                type="Vendor\Module\Model\Product"/>
</config>

How It Works

// Original class
namespace Magento\Catalog\Model\Product;
class Product {
    public function getName() { return $this->name; }
}

// Your replacement
namespace Vendor\Module\Model;
class Product extends \Magento\Catalog\Model\Product {
    public function getName() {
        return parent::getName() . ' (Modified)';
    }
}

When ObjectManager creates Product, it actually creates your Vendor\Module\Model\Product.

Interface Preferences

<preference for="Magento\Catalog\Api\ProductRepositoryInterface"
            type="Vendor\Module\Api\ProductRepository"/>

This replaces the default implementation of the interface.

When to Use Preferences

Appropriate Use Cases

  1. Replacing default implementations of interfaces
<preference for="Magento\Search\Model\SearchEngineInterface"
            type="Vendor\CustomSearch\Model\SearchEngine"/>
  1. Adding behavior to classes without events/plugins
// Override save() to add custom validation
public function save() {
    $this->validateCustomFields();
    return parent::save();
}
  1. Fixing bugs in core classes (temporary, then upgrade)
public function getData($key = null) {
    // Fix for known bug
    if ($key === 'special_field') {
        return $this->fixSpecialField();
    }
    return parent::getData($key);
}
  1. Adding methods to existing classes
public class ExtendedProduct extends Product {
    public function getExtendedData() {
        // New method not in original class
    }
}

Not Appropriate For

  • Modifying behavior that plugins can handle
  • Adding side effects (use observers)
  • Temporary overrides (use plugins or config)
  • Replacing core classes without clear need

Preference Limitations and Risks

Only One Preference Per Class

Only one preference can exist for any class or interface. If two modules define preferences for the same class, one wins based on module load order.

<!-- Module A -->
<preference for="Magento\Catalog\Model\Product" type="Vendor\A\Product"/>

<!-- Module B -->
<preference for="Magento\Catalog\Model\Product" type="Vendor\B\Product"/>

<!-- Only one will be used — unpredictable which one wins -->

Upgrade Fragility

Preferences override the entire class. When Magento upgrades and changes the original class, your preference may break.

// Your preference from Magento 2.4.3
public function save() {
    // Override based on original implementation
    $this->validate();
    parent::save();
}

// Magento 2.4.4 changes save() internals
// Your preference breaks silently or throws errors

Cannot Compose

Preferences cannot be composed. You cannot stack multiple preferences on the same class.

Testing Difficulty

Preferences make testing harder because they replace the entire class. Unit tests may need to mock the full class instead of just the interface.

Performance Impact

Preferences affect all instances of a class across the entire application, not just specific method calls.

Plugin Advantages Over Preferences

Composability

Multiple plugins can coexist on the same class:

<!-- Module A -->
<type name="Magento\Catalog\Model\Product">
    <plugin name="module_a" type="Vendor\A\Plugin" sortOrder="10"/>
</type>

<!-- Module B -->
<type name="Magento\Catalog\Model\Product">
    <plugin name="module_b" type="Vendor\B\Plugin" sortOrder="20"/>
</type>

Both plugins execute without conflict.

Granular Control

Plugins target specific methods:

<type name="Magento\Catalog\Model\Product">
    <plugin name="enhance_name" type="Vendor\Plugin\ProductNamePlugin"/>
</type>

Only getName() is affected; other methods remain untouched.

Easy Disabling

<type name="Magento\Catalog\Model\Product">
    <plugin name="third_party_plugin" disabled="true"/>
</type>

Disable without removing code.

Upgrade Safety

Plugins survive Magento upgrades because they wrap methods rather than replacing classes. If the original method changes, the plugin continues to work.

Comparison Table

Aspect Plugin Preference
Scope Method-level Class-level
Multiple Yes (composable) No (one per class)
Granularity Specific methods Entire class
Upgrade safety High Low
Disabling Easy (disabled flag) Requires removing
Can add methods No Yes
Can skip methods Yes (around) Yes (override)
Testability High Medium

Practice Problems

0 / 1 solved
Preference Conflict

Two modules both define a preference for the same interface. How do you resolve this?

Quiz

1. How many preferences can exist for a single class?

Question 1 options

2. What is a key advantage of plugins over preferences?

Question 2 options

3. When should you use a preference?

Question 3 options

4. What happens when two modules define preferences for the same class?

Question 4 options

Flashcards

Question

How many preferences per class?

Answer

Only one preference can exist for any class or interface

Question

Can multiple plugins coexist on the same class?

Answer

Yes, plugins are composable with sort_order controlling execution

Question

Which is more upgrade-safe, plugins or preferences?

Answer

Plugins — they wrap methods rather than replacing entire classes

Question

Can a plugin add new methods to a class?

Answer

No, plugins can only intercept existing public methods

Question

When is a preference appropriate?

Answer

When replacing the default implementation of an interface

Revision Notes

Key Takeaways

  • 1. Preferences replace an entire class via DI; only one preference per class/interface
  • 2. Plugins are composable — multiple plugins can target the same class
  • 3. Preferences are fragile across upgrades; plugins survive upgrades
  • 4. Use preferences to replace interface implementations, not for method-level changes
  • 5. Plugins offer granular control, easy disabling, and better testability
  • 6. Prefer plugins over preferences unless you need full class replacement

Interview Tips

  • Explain the fundamental difference between preferences and plugins
  • Discuss why preferences are risky for upgrades
  • Give examples of when a preference is actually appropriate
  • Explain how to resolve preference conflicts between modules

Cheat Sheet

Plugin vs Preference Cheat Sheet

Preference:

  • Replaces entire class
  • Only one per class/interface
  • Use for interface implementations
  • Fragile on upgrades

Plugin:

  • Wraps specific methods
  • Multiple composable
  • Use for method modification
  • Upgrade-safe

Decision:

  • Need to replace implementation? -> Preference
  • Need to modify method behavior? -> Plugin
  • Need to add side effects? -> Observer
  • Need to add methods? -> Preference (carefully)