Developer Journal

Intermediate 6 min read

Making Drupal Scaffold Customizations Survive Composer Updates

Preserve project-specific changes to Drupal's .htaccess and robots.txt with Composer Scaffold file mappings so they survive Drupal core updates.

Last updated August 8, 2026

Composer-managed Drupal projects make core updates safer, but files such as .htaccess, robots.txt, and default.settings.php are generated by Drupal's Composer Scaffold system. Project-specific edits to those files need a reproducible home or a future Composer operation can replace them.

Identify scaffold-managed files

While reviewing this site's Drupal 11 deployment workflow, I found three locally modified files that are supplied by Drupal core:

  • web/.htaccess
  • web/robots.txt
  • web/sites/default/default.settings.php

Comparing them with the source files under web/core/assets/scaffold/files confirmed that the working copies had originally diverged from Drupal's scaffold output.

Two of those differences represented behavior I wanted to preserve: a canonical hostname redirect and a sitemap declaration. The customization to default.settings.php, however, no longer belonged there because the real configuration sync path was already handled by the site's tracked settings.php.

Keep Drupal scaffold files close to core

Instead of maintaining complete customized copies of Drupal's scaffold files, I restored them to the versions supplied by core and moved only the project-specific additions into dedicated scaffold fragments.

The project now contains:

assets/scaffold/htaccess-prepend.txt
assets/scaffold/robots-append.txt

The .htaccess fragment contains the canonical hostname redirect:

# Use the www hostname as the single public, canonical URL.
<IfModule mod_rewrite.c>
  RewriteEngine on
  RewriteCond %{HTTP_HOST} ^pederklockmann\.com$ [NC]
  RewriteRule ^(.*)$ https://www.pederklockmann.com/$1 [R=301,L,NE]
</IfModule>

The robots fragment contains the sitemap declaration:

Sitemap: https://www.pederklockmann.com/sitemap.xml

Configure Composer Scaffold file mappings

Drupal's Composer Scaffold plugin supports project-level file mappings with prepend and append operations. I added mappings for the two customized files in composer.json:

{
  "extra": {
    "drupal-scaffold": {
      "locations": {
        "web-root": "web/"
      },
      "file-mapping": {
        "[web-root]/.htaccess": {
          "prepend": "assets/scaffold/htaccess-prepend.txt"
        },
        "[web-root]/robots.txt": {
          "append": "assets/scaffold/robots-append.txt"
        }
      }
    }
  }
}

Drupal still supplies the base files. The application repository owns only the additions that are unique to this site.

Choose prepend or append deliberately

The canonical redirect needs to run before Drupal's normal rewrite handling, so the .htaccess fragment is prepended.

The sitemap declaration simply needs to be present in robots.txt, making append the natural choice.

This also makes the relationship clear when another developer reads the Composer configuration. These files are not complete replacements for Drupal's defaults.

Regenerate and verify the scaffold

After configuring the mappings, I regenerated the scaffold files:

composer drupal:scaffold

The resulting web/.htaccess began with the canonical redirect and then contained Drupal's current scaffold content. The generated web/robots.txt ended with the project's sitemap declaration.

I also compared default.settings.php directly with the Drupal core scaffold source and confirmed it was byte-for-byte identical.

Prove the customizations survive a core update

The most useful test came immediately afterward when I updated the site from Drupal 11.4.4 to Drupal 11.4.5.

Composer regenerated the scaffold-managed files as part of the update, and both project customizations remained intact.

That is the important difference between a manual edit and a reproducible scaffold customization. The next core update can replace Drupal's portion of the file without losing application-specific behavior.

Keep runtime settings out of default.settings.php

The same cleanup also reinforced an important distinction around Drupal settings files.

default.settings.php is an example supplied by Drupal core. Application-specific runtime behavior belongs in the site's actual settings.php or another intentional environment-specific settings include.

Keeping the example file pristine makes Drupal core updates easier to review and reduces the amount of scaffold content the project needs to maintain.

Key Takeaways

  • Identify which files in a Composer-managed Drupal project are owned by Composer Scaffold before customizing them.
  • Keep project-specific additions in small prepend or append fragments instead of maintaining complete copies of core scaffold files.
  • Keep default.settings.php close to Drupal core and put real runtime settings in the site's actual settings configuration.
  • Regenerate scaffold files and verify the final output before committing changes.
  • Test scaffold customizations during a real Drupal core update to prove they are reproducible.

Further Reading