Is there any performance difference between duplicating composer packages among multiple plugins and not doing it? How can I avoid it?

There are no performance issues with duplicating composer packages.

If you look at the file vendor/composer/autoload_classmap.php, you will see lines like these:


// autoload_classmap.php @generated by Composer

$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);

return array(
    'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
    'Codeception\\Exception\\ConnectionException' => $vendorDir . '/codeception/module-webdriver/src/Codeception/Exception/ConnectionException.php',

Being loaded during composer activation, this film establishes a mapping of namespaces to certain folders. A similar meaning has the file vendor/composer/autoload_psr4.php.

Now let us look at the situation when two plugins (A and B) have the same packages (Stripe SDK, for instance). When plugin A is loaded, the composer establishes the mapping of the Stripe SDK namespace to a folder in plugin A. During the loading of plugin B, its class mapping of the SDK is ignored, and plugin B uses Stripe SDK from plugin A.

Plugins are loaded in alphabetic order, so SDK from plugin A will always be used when both plugins are active. If you deactivate plugin A, SDK from plugin B will be used in B.

This causes an evident problem if plugins A and B have different SDK versions. If B tends to use a higher SDK version and tries to use a method which does not exist in an older version (which is in A), it will cause a fatal error.

To avoid this possibility, some very advanced packages, like Action Scheduler by Automattic, have a dedicated code allowing to load a small portion of the package from all plugins and later, on a hook, determine the highest available version of Action Scheduler and load it.

But from the performance point of view, class autoloading has no issues. SDK is loaded only once, and we have no excessive memory consumption.

You can check it by the following mu-plugin:

use Symfony\Polyfill\Php80\Php80;

function my_autoload_test() {
    if ( ! class_exists( Php80::class ) ) {

    $php80     = new Php80();
    $reflector = new ReflectionClass( $php80 );

    error_log( $reflector->getFileName() );

add_action( 'init', 'my_autoload_test' );

Install and activate two well-known plugins: BackWPup and WooCommerce. Both use the same package, symfony/polyfill-php80. The code above logs where the class Php80 is used from.

When both plugins are active, we have a path like ...\wp-content\plugins\backwpup\vendor\symfony\polyfill-php80\Php80.php.

When we deactivate BackWPup, we have a path like ...\wp-content\plugins\woocommerce\vendor\symfony\polyfill-php80\Php80.php.

Composer is a great tool to load packages only once and prevent memory bloating.