How can I get, code wise, the list of the installed modules and their version listed in composer?

I need something like this (format is just as an example. It's not really important):

        'name' => 'magento/module-catalog',
        'version' => '101.1.0'
        'name' => 'magento/module-cms',
        'version' => '101.1.0'

I tried \Magento\Framework\Composer\ComposerInformation::getInstalledMagentoPackages() and getSystemPackages(), but both return and empty array.

I suspect this might happen because I didn't install Magento 2 via composer. I just cloned the guthub repo.

But this is not a solution. I need something that will work on both install methods (composers and clone repo).


Maybe my code can be useful for you (tested in the observer):

 * @var \Magento\Framework\App\DeploymentConfig
protected $deploymentConfig;

 * @var \Magento\Framework\Component\ComponentRegistrarInterface
protected $componentRegistrar;

 * @var \Magento\Framework\Filesystem\Directory\ReadFactory
protected $readFactory;

 * @param \Magento\Framework\App\DeploymentConfig $deploymentConfig
 * @param \Magento\Framework\Component\ComponentRegistrarInterface $componentRegistrar
 * @param \Magento\Framework\Filesystem\Directory\ReadFactory $readFactory
public function __construct(
    \Magento\Framework\App\DeploymentConfig $deploymentConfig,
    \Magento\Framework\Component\ComponentRegistrarInterface $componentRegistrar,
    \Magento\Framework\Filesystem\Directory\ReadFactory $readFactory
) {
    $this->deploymentConfig = $deploymentConfig;
    $this->componentRegistrar = $componentRegistrar;
    $this->readFactory = $readFactory;

 * Get module composer version
 * @param $moduleName
 * @return \Magento\Framework\Phrase|string|void
public function getModuleVersion($moduleName)
    $path = $this->componentRegistrar->getPath(
    $directoryRead = $this->readFactory->create($path);
    $composerJsonData = $directoryRead->readFile('composer.json');
    $data = json_decode($composerJsonData);

    return !empty($data->version) ? $data->version : __('Read error!');

 * Collect enabled modules version
 * @param Observer $observer
public function execute(Observer $observer)
    $modules = $this->deploymentConfig->get('modules');
    $modulesWithVersion = [];
    foreach ($modules as $moduleName => $isEnabled) {
        if (!$isEnabled) {

        $modulesWithVersion[$moduleName] = $this->getModuleVersion($moduleName);
  1. Collects all enabled module names from the config
  2. Reads their composer.json one-by-one and saves version

Result (in debug):


  • this looks clean. I'll give it a shot and come back. – Marius May 12 '17 at 9:25
  • 1
    I can confirm this works. I had to do some changes, because some (custom) modules might not have composer.json and it gives an error. But it was easy to work around it. I also used $data->name instead of $moduleName in the return array, because that's what I needed. Thanks. – Marius May 12 '17 at 12:56
  • @Marius I'm glad to help you. Feel free to improve my answer if you could make it more helpful for others. – Siarhey Uchukhlebau May 12 '17 at 13:15
  • I have nothing to improve. The idea is there. If someone needs a really custom thing, let them work for it. – Marius May 12 '17 at 13:25

I need something that will work on both install methods (composers and clone repo).

That's probably the tricky part as you said because you can't use the Composer packages classes directly when installed via GitHub.

My suggestion would be to loop through the modules folder and use a mix of the following:

  • Magento\Framework\Composer\ComposerJsonFinder::findComposerJson() to find the composer.json file
  • then use \Composer\Factory::create(new BufferIo(), $composerJsonFile) to create a composer instance.
  • once you have that , I'm pretty sure you can call getConfig() on the Composer file to get the details of that file.

NB: all I'm saying here is highly theorical based on my assumptions

  • This sounds like a lot of work. I could simply do a glob and turn JSON into array and read it from there, but I was hoping for a clean solution. +1 though. It looks like a valid solution, at least theoretically. – Marius May 12 '17 at 8:21
  • @Marius yeah as I said I don't think there's a quick and clean solution when you have a non composer M2 install unfortunately :( – Raphael at Digital Pianism May 12 '17 at 8:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.