Enabling CSS aggregation for fewer HTTP requestsfor Drupal 11 , 10 , 9 , and 8

Last updated :  

Every unstyled flash of a page you've ever seen while a site loads is really a story about HTTP requests: your browser has to fetch every single CSS file a Drupal site's modules and theme have attached, one connection at a time, before it can even start painting the page. A site with 20 small stylesheets doesn't load 20x faster than one with a single big one — it's often slower, because each request carries its own connection overhead. CSS aggregation is Drupal's built-in fix: instead of shipping dozens of separate files, it bundles them into one (or a handful) at request time, and caches the result.

What you'll learn in this lesson

  • Why many small CSS files are usually slower than one bundled file, not faster
  • How to turn on CSS aggregation from the admin UI, and what actually happens when you do
  • Where the aggregated files end up on disk, and how Drupal knows when to regenerate them
  • Why aggregation should always be off during active theme development

Turning it on

Aggregation is a single checkbox, at Configuration → Development → Performance (/admin/config/development/performance), under "Bandwidth optimization":

  • Aggregate CSS files — combines every attached stylesheet into one (or a few, grouped by weight/media type) minified file per page.
  • Aggregate JavaScript files — the JS equivalent, covered in the next lesson.

You can also set this permanently in code, which is the right move for a production site whose settings.php is version-controlled:

// In settings.php, for a production environment:
$config['system.performance']['css']['preprocess'] = TRUE;
$config['system.performance']['js']['preprocess'] = TRUE;

What actually happens under the hood

Drupal doesn't aggregate on every request — that would be far too slow. The first time a given combination of CSS files is needed, Drupal's asset optimizer bundles and minifies them once, then writes the result to public://css/ as a file with a hash in its name (something like css_9f8a3e...css). Every subsequent request for that same combination of files just serves the already-built file straight from disk. The hash is derived from the exact set of files and their content, so if a module updates its CSS or you add a new library, Drupal generates a fresh aggregate automatically — you don't have to remember to clear anything yourself in normal operation.

Turn this off while developing your theme. With aggregation on, every CSS tweak you make requires a full cache rebuild (drush cr) before you'll see it reflected in the aggregated file, which makes for a miserable edit-refresh loop. Keep it disabled locally, and only enable it for staging/production — exactly the kind of environment-specific setting settings.local.php exists for.

See it for yourself

Visit /admin/config/development/performance on your own Drupal site, enable "Aggregate CSS files," save, then view any page's source — instead of a dozen <link rel="stylesheet"> tags pointing at individual module/theme CSS files, you'll see one or two pointing at /sites/default/files/css/css_....css.

Quick check: you just edited a contributed module's CSS file directly and refreshed the page, but your change isn't showing up even though aggregation was already on before you started. What's the most likely reason, and what's the fix? (Because the aggregated file was already built and cached before your edit — Drupal doesn't watch source files for changes. Run drush cr to clear the render/asset caches and force a fresh aggregate to be built.)

Key takeaways

  • CSS aggregation bundles every attached stylesheet into a small number of cached files, trading many small HTTP requests for one or two larger ones.
  • Toggle it at /admin/config/development/performance, or set it permanently via $config['system.performance']['css']['preprocess'] in settings.php for production.
  • Aggregated files are cached to public://css/ with a content-derived hash — Drupal regenerates them automatically when the underlying CSS changes, no manual cache-clear needed in normal operation.
  • Always disable aggregation in local development — it adds a cache-rebuild step to every CSS change you make.

Coming up next

CSS aggregation solves half the "too many small files" problem. The other half is JavaScript — and it comes with an extra wrinkle, since script execution order actually matters. Next up: Aggregating JavaScript Files.