Configuration Manager or hook_update() to enable modules In Drupal 7, if we wanted to push code to our environments enabling modules, we would call module_enable() in hook_update_N(). We no longer have that in Drupal 8, so how do we programmatically enable modules? Do we use Drupal 8's Configuration Manager or hook_update_N()?

A diff on the exported configuration yields this:

+++ b/cim/sync/core.extension.yml
@@ -10,6 +10,9 @@ module:
   config: 0
   contact: 0
   contextual: 0
+  ctools: 0


So it seems the module is enabled via code using Configuration Manager.
We're also working with the idea of this:

function mymodule_update_8003() {
  $modules = array(
    'ctools',
  );
  \Drupal::service('module_installer')-&gt;install($modules);
}


What is the correct method?
For site-specific changes, I would definitely go with using configuration deployments.

They have a very interesting advantage and difference to enabling modules in update hooks/through the API yourself. Config deployments can handle changed default configuration while installing the module.

A module might provide default configuration like views, settings and so on. They might also programatically do things during hook_install() that you want to customize (like configuring default formatters/widgets for fields they add) Configuration deployment allows you install a module locally, customize it and deploy the result as an atomic operation (as much as is possible) to production.

I'd only use the API and hook_update_N() if it's a functional change in a module, e.g. when a module is split up into a new one and/or has a new dependency that is mandatory for it to work.

Also note that I would advice against doing both in the same deployment. Update hooks might run code and create config that will result in differences on every run (like creating a new configurable field). Running config deployments first isn't possible anyway and will soon be prevented explicitly in core and running after might result in the deployment removing and re-adding configuration due to different UUID's.