My Drupal Project Setup

Like most people, I use drupal-project for creating new Drupal 8 sites. However, I typically make a few adjustments for my baseline site. This is what my edited composer.json usually looks like right before site-install:

    "name": "drupal-composer/drupal-project",
    "description": "Project template for Drupal 8 projects with composer",
    "type": "project",
    "license": "GPL-2.0-or-later",
    "authors": [
            "name": "",
            "role": ""
    "repositories": [
            "type": "composer",
            "url": ""
    "require": {
        "php": ">=7.2", // Note 1
        "composer/installers": "^1.2",
        "cweagans/composer-patches": "^1.6.5",
        "drupal-composer/drupal-scaffold": "^2.5",
        "drupal/core": "8.7.6", // Note 2
        "drush/drush": "^9.0.0",
        "vlucas/phpdotenv": "^2.4",
        "webflo/drupal-core-strict": "8.7.6", // Note 3
        "webflo/drupal-finder": "^1.0.0",
        "webmozart/path-util": "^2.3",
        "zaporylie/composer-drupal-optimizations": "^1.0"
    "require-dev": {
        "drupal/console": "^1.0.2", // Note 5
        "webflo/drupal-core-require-dev": "8.7.6" // Note 3
    "conflict": {
        "drupal/drupal": "*"
    "minimum-stability": "dev",
    "prefer-stable": true,
    "config": {
        "apcu-autoloader": true, // Note 6
        "bin-dir": "bin/", // Note 4
        "platform": {
            "php": "7.2" // Note 1
        "optimize-autoloader": true, // Note 6
        "sort-packages": true
    "autoload": {
        "classmap": [
        "files": ["load.environment.php"]
    "scripts": {
        "pre-install-cmd": [
        "pre-update-cmd": [
        "post-install-cmd": [
        "post-update-cmd": [
    "extra": {
        "composer-exit-on-patch-failure": true,
        "patchLevel": {
            "drupal/core": "-p2"
        "installer-paths": {
            "web/core": ["type:drupal-core"],
            "web/libraries/{$name}": ["type:drupal-library"],
            "web/modules/contrib/{$name}": ["type:drupal-module"],
            "web/profiles/contrib/{$name}": ["type:drupal-profile"],
            "web/themes/contrib/{$name}": ["type:drupal-theme"],
            "drush/Commands/{$name}": ["type:drupal-drush"]
        "drupal-scaffold": {
            "initial": {
                ".editorconfig": "../.editorconfig",
                ".gitattributes": "../.gitattributes"

That has some non-compliant JSON it in, so I can talk about my customizations.

Note 1: Minimum PHP Version

Drupal 8 currently supports PHP 5.6 (though it is on its way out). On my local machine and my servers, I have PHP 7.2 installed. I specify here as a requirement in case I accidentally have my MAMP using 5.6 or 7.0 for testing purposes. I also add this is a platform requirement, which is a recommendation in the, which can lead to better composer choice dependencies.

Note 2: Pin Core

I am very cautions about updating composer dependencies, especially core. Every time a new version of core comes out, I carefully read the changelog and test (and see what update hooks will run). This is especially important when updating between minor versions (say 8.6.X to 8.7.x). To protect myself (and my team) against problems, I will "pin" core to a specific version instead of using a tilde or caret constraint.

Note 3: Pin Core Dependencies

I also rely on webflo/drupal-core-strict and webflo/drupal-core-require-dev to keep core dependencies aligned with what TestBot runs. So, I also pin these to the same core version to be safe. This can help a lot when updating between minors, or when updating Drush or Drupal Console.

Note 4: Move Executables

This is a little nicety (and not needed if you use direnv). I pull the bin directory out of vendor and place it at the top level of the project.

Note 5: Drupal Console

This is going to be controversial. I like Drupal Console and use it on my local machine for development. However I do not use it on remote servers (neither dev, staging, nor production). So, I install it as a development dependency. On remote servers (and in pipelines), I use Drush, but that is limited to drush cr, drush cim, and drush cex.

Note 6: Additional Configuration

I also set apcu-autoloader and optimize-autoloader to true, which can lead to some performance improvements. Note that I don't add an explicit requirement on "ext-apcu" because my PHP CLI doesn't find it, and I am too lazy to fix it.

The Result

After using this file, I do a

composer update

to rebuild the composer.lock file and install my dependencies before site installation. On my remote servers (or in build pipelines), I do

composer install --no-dev

to install my non-development dependencies.