Drupal hosting is where most of the “Drupal is slow” reputation comes from, and it is almost always a purchasing decision rather than a software problem. A site gets built properly, then goes live on a plan priced for a brochure site with a handful of PHP files. The result is a content management system with a serious render pipeline running inside a memory limit it cannot change, on an opcode cache it does not control, with no shell to run its own tooling.

The comparison people make in their heads is with WordPress, and it is the wrong one. WordPress runs acceptably on almost anything because its market share forced hosts to make it run acceptably on almost anything. Drupal assumes a current PHP, a recent database, a real cache backend, a command line, and a deployment process that treats the codebase as a build artefact rather than a folder you edit.

What does Drupal actually need from a host? A PHP version at or above the floor for your release, a current MySQL, MariaDB or PostgreSQL, 256MB of PHP memory in practice, OPcache, shell access for Composer and Drush, a real cron entry, and an external object cache once you have logged-in users. Cheap shared hosting fails three or four of those at once.


What Drupal Actually Requires From a Server

The published requirements are short, specific and public, and almost nobody reads them before buying. They are also version-specific in a way that matters right now, because two of the floors move in December 2026.

The PHP version floor is not negotiable

Drupal 11 requires PHP 8.3 as a minimum and supports 8.3, 8.4 and 8.5. Drupal 10 requires 8.1 and supports up to 8.4, and Drupal 12 raises the floor again to PHP 8.5. Those numbers come from Drupal’s own PHP requirements documentation, which is the only version of the list worth trusting.

This matters more than it looks, because the PHP branches themselves expire. php.net’s supported versions page puts the end of security support for PHP 8.2 at 31 December 2026, with 8.3 running to 31 December 2027 and 8.4 to 31 December 2028. PHP 8.1 is already past it. A host advertising “PHP 8.1 and 8.2 available” is offering a stack that is unpatched now or unpatched within months.

The two dates collide. Drupal 10 reaches end of life on 9 December 2026 and Drupal 12 ships the same week, according to the core release schedule. If your host cannot serve PHP 8.3 or newer, you cannot run a supported Drupal after that. Our guide to Drupal migration costs, options and deadlines covers what that means if you are still on 10.

Database engines and their real minimums

Drupal 11 wants MariaDB 10.6 or later, MySQL 8.0 or later, PostgreSQL 16 or later, or SQLite 3.45 or later, per the database server requirements. Drupal 10 is more forgiving at MariaDB 10.3.7, MySQL 5.7.8, PostgreSQL 12 and SQLite 3.26, which is exactly why an upgrade sometimes forces a database upgrade the client was not expecting.

Two details get skipped. InnoDB must be the storage engine on MySQL and MariaDB, because Drupal relies on transactions and row-level locking. On PostgreSQL, the pg_trgm extension has to be created on the Drupal database before installation, and a managed database service that does not let you run CREATE EXTENSION is not usable.

SQLite is genuinely supported and fine for local development, but it is not a production answer once several editors are saving content, because write concurrency becomes the ceiling first.

Memory, extensions and the web server

Drupal’s documented minimum is 64MB of PHP memory, and it shows warnings below that. The same page notes that 128MB or 256MB is typical on production and that media-heavy installations need more. In practice, treat 256MB as the working figure and expect to raise it for the command line, because Composer and large migrations are the memory-hungry operations, not page serving.

The extension list is unremarkable and worth checking anyway: PDO with a database driver, XML, JSON, mbstring, cURL, OpenSSL for outbound HTTPS, and either GD or ImageMagick for image derivatives. Drupal 12 adds Argon2 for password hashing, which is one more thing a very old PHP build will not have.

On the web server, Drupal supports Apache 2.4.7 or later and Nginx 1.1 or later, and does not support Microsoft IIS as of Drupal 11.0.0. Apache needs mod_rewrite for clean URLs and AllowOverride All so the shipped .htaccess applies. That last point catches people: some of Drupal’s protective rules exist only in .htaccess, so an Nginx deployment has to reproduce them in the server configuration by hand. It is a routine step that is routinely skipped, and it is one of the first things we look for in a server security audit.

Why Shared Hosting Fails Drupal

Shared hosting is not bad hosting. It is hosting optimised for a different application shape, and Drupal breaks against its constraints in four predictable places.

No shell means no Composer and no Drush

Modern Drupal is a Composer project. Core, contributed modules and their PHP dependencies are all resolved by Composer, and once Composer manages one module it has to manage core as well. Mixing Composer with manual file updates is how a site ends up unable to update at all.

A control panel with a file manager cannot do that. Neither can an FTP client. Without SSH you also lose Drush, which is how cache rebuilds, configuration imports, database updates and user password resets are actually performed. A site you cannot run drush cr against is a site where every recovery step becomes a support ticket.

The limits you cannot see, let alone change

A shared account gives you a memory_limit set by someone else, usually 128MB and sometimes lower, with no route to raise it for the one migration that needs 512MB.

OPcache is the bigger problem. It stores precompiled script bytecode in shared memory so PHP does not reparse files on every request, and on a shared host that memory pool is shared across hundreds of accounts. Drupal has thousands of PHP files, so it is a heavy tenant of a pool it is competing for, and it gets evicted. The symptom is a site that is quick for a minute after a visit and slow again an hour later.

Then there is what is missing entirely: no Redis, no Memcached, no control over the PHP process manager, and no way to run a long queue worker.

Cron that never really runs

Drupal’s Automated Cron module runs every three hours by default and is triggered by end users visiting the site. On a busy site that means a visitor occasionally pays for search indexing with their page load. On a quiet site it means cron effectively does not run, so the search index goes stale, log tables never get trimmed and available security updates are never checked.

The documentation recommends triggering cron externally instead, because it always runs on schedule and uses fewer resources. That needs a real crontab entry, which the cheapest tier does not provide.

The Caching Layers and Which One Your Visitor Hits

Drupal has more caching than most people realise, and the layers are not alternatives. They stack, and each one catches what the layer above it could not.

OPcache sits below Drupal entirely

OPcache is not a Drupal feature. It caches compiled PHP bytecode at the interpreter level, so it applies to every request whether or not any Drupal cache hits. Get this wrong and nothing above it can compensate, because every request pays to recompile the framework before it reaches the router. Size the shared memory generously and disable timestamp validation in production, where the file set only changes on deployment.

Internal Page Cache and Dynamic Page Cache

Internal Page Cache is a core module, enabled by default, and it serves anonymous users only. It assumes every anonymous visitor sees the same page, stores the whole response on first request, and reuses it. For a marketing site with no personalisation, this is the layer that does almost all the work.

Dynamic Page Cache is also core and also enabled by default, and it caches for anyone, including authenticated users. It works by having the render system turn the genuinely personal parts of a page into placeholders, caching everything around them. That is why a logged-in Drupal page can still be mostly cached: only the user menu and a few blocks are actually dynamic.

BigPipe and the render cache

Below both sits the render cache, which caches individual blocks, fields, views results and entity renders. A page that misses the page cache is usually assembled largely from render cache hits rather than rebuilt from the database.

BigPipe handles what is left. It has been in core since Drupal 8.1, stable since 8.3, and in the standard install profile since 8.5. Instead of waiting for every placeholder to resolve, it flushes the cacheable page immediately and streams the personalised fragments in afterwards. It needs no configuration, and it helps authenticated users far more than anonymous ones.

So the anonymous visitor on a well-configured site hits Internal Page Cache, or the CDN in front of it, and never touches most of this. The logged-in editor hits Dynamic Page Cache, the render cache and BigPipe on every request, which is why authenticated traffic costs so much more.

The external object cache

Every layer above needs somewhere to store its entries. By default that is the database, in cache tables, which means your cache reads compete with your content queries on the same server.

The Redis module moves cache, lock, flood and queue backends onto Redis or a compatible store such as Valkey, using either the PhpRedis extension, the Relay extension or the pure-PHP Predis library. Memcached is the equivalent alternative. For a small anonymous site this changes little. For a site with logged-in users it is usually the single largest available improvement, because it removes the noisiest write load from the database and makes locking cheap.

Reverse Proxy and CDN in Front of Drupal

A reverse proxy such as Varnish or Nginx, or a CDN, answers requests before PHP is involved at all. For anonymous traffic this is the difference between serving a page in single-digit milliseconds and serving it in a few hundred. It is also the layer people are most afraid of, because a stale cache on a news site or a shop is a visible failure.

Cache tags are what make a CDN safe

Drupal’s answer is cache tags. Cache tags describe data dependencies, written as strings like node:5, user:3 or node_list. Every cached item records which tags it depends on, so editing node 5 invalidates every cached fragment, page and view that referenced it, wherever it appeared.

The important part is that Drupal can publish those tags outward. Contributed modules emit them as a Surrogate-Key header for Fastly or a Cache-Tag header for Cloudflare, and the CDN then purges by tag when Drupal says so. That converts a CDN from a time-based gamble into an event-driven cache: you can set a long time to live, because an edit purges exactly the affected URLs within seconds.

Watch the header budget. Cloudflare’s purge by cache tag documentation caps the aggregate Cache-Tag header at 16KB after the field name, roughly 1,000 unique tags, with a maximum of 1,024 characters per tag in an API call and 100 tags per dashboard purge. A Drupal view listing many entities can generate far more tags than that, so a page that lists everything will silently overflow the header unless the module is configured to trim or hash them.

Choosing Drupal Hosting: Four Tiers, Honestly

There are four real options, and the correct one is decided by whether you have authenticated traffic and whether you have anyone to operate the server. The bands below are what UK clients typically pay in our experience, exclusive of VAT, and are indicative rather than quoted from any vendor.

TierTypical monthly costWhat it buys
SharedGBP 3 to GBP 15Nothing Drupal needs
Unmanaged VPS or cloudGBP 20 to GBP 120Full control, no operator
Managed Drupal platformGBP 40 to GBP 800 and upOpinionated stack and workflow
Custom infrastructureGBP 400 upwardsEverything, plus the obligation

Shared hosting

Suits nobody running Drupal in production. It fails on shell access, memory, opcode caching, object caching and cron simultaneously. If budget genuinely caps here, a small unmanaged instance at a similar price is a better use of the money.

Unmanaged VPS or cloud instance

Roughly GBP 20 to GBP 120 a month buys a machine with full root, which suits the large majority of Drupal sites. You choose the PHP version, size OPcache, install Redis, set a crontab and configure Nginx properly. What you do not get is anyone to do it, patch it, monitor it or restore it at 2am. This tier is correct when you have a developer or agency on retainer, and the retainer is the real cost, not the instance.

Managed Drupal specialist platforms

Managed Drupal hosting starts around GBP 40 a month for a small site and rises quickly with traffic, environments and support tier. What you buy is an opinionated stack that is already correct, plus Git-based deployment, staging environments, backups and someone who understands Drupal answering the phone. It is good value when the alternative is nobody, and poor value when you pay platform prices for a brochure site that gets 4,000 visits a month.

Full custom infrastructure

Separate database, dedicated cache nodes, application servers behind a load balancer, object storage for files. This starts to make sense above roughly GBP 400 a month, and only when authenticated traffic, integrations or compliance requirements make the managed tiers awkward. It is the most capable tier and the most demanding, because you now own patching, monitoring and disaster recovery. Our Drupal web development guide covers where that complexity comes from on the application side.

Deployment: You Do Not Edit Files on the Server

Because Composer resolves the entire dependency tree, the server’s codebase is an output, not a workspace. Editing a module file in place means the next composer update overwrites it, and it means your production code no longer matches anything in Git.

A sane release process builds the artefact somewhere else. Run composer install from the committed composer.lock in CI, so the build is reproducible and the production host never needs Composer, PHP memory for dependency resolution, or write access to vendor. Ship the result, run database updates, import configuration, rebuild caches. Roll back by pointing at the previous artefact.

That also settles the hosting question quietly. A host that expects you to edit files over FTP is incompatible with the way Drupal is maintained, whatever its specification sheet says.

Where configuration synchronisation fits

Drupal keeps active configuration in the database and exports it to YAML files, which is how content types, fields, views and settings move between environments. The configuration management documentation explains that the site UUID has to match between source and destination, which is the usual reason a first import fails.

Practically, this means configuration is code. It is committed, reviewed and deployed with the rest, and the import step runs as part of the release rather than being clicked through in the admin interface afterwards. Hosting has to support that: you need a place to run the import, and an environment where a failed import can be rolled back rather than half-applied to production.

Files, Media and Backups

Drupal has two file systems and the difference is load-bearing. The public one lives under the web root and is served directly by the web server. The private one lives outside the web root, and every request for a private file passes through Drupal so that access can be checked.

Private files are therefore far more expensive than public ones, because each download bootstraps PHP, so a site serving large private documents needs headroom a static file server would not.

Offloading media to object storage

Once files live on the application server, horizontal scaling and rebuilds become painful, and every backup carries the whole media library. Moving the public file system to S3-compatible object storage separates the two, lets the CDN serve media directly, and makes an application server genuinely disposable.

A restore test proves what a backup cannot

A backup proves a file exists. A restore test proves the file is complete, that the database and the files are from the same moment, that your credentials still work, and that you know how long it takes. Those are four separate failure modes and none of them are visible from a green tick in a control panel.

Test it against a real timer at least twice a year and write the number down. If the restore takes six hours and your tolerance is one, the architecture is the problem, not the backup. Recovery time is a hosting requirement, and it belongs in the specification rather than in an incident.

Sizing a Drupal Host Properly

Pageviews are the wrong unit. A site with 200,000 anonymous monthly pageviews behind a CDN can be comfortable on a small instance, while a site with 8,000 pageviews can struggle if most of them are logged in.

Authenticated traffic is the real driver

Anonymous requests can be answered by the page cache or the CDN without touching PHP. Authenticated requests cannot. Every one of them runs the render pipeline, checks access on each entity, resolves placeholders and writes session data. The practical question is not how many visits you get, it is how many concurrent logged-in users you have, and what those users are allowed to see.

Editors are the extreme case. Content administration screens are among the heaviest pages in Drupal, and they are uncacheable by definition, so a site with twelve editors working simultaneously has a genuine concurrency requirement that its public traffic never suggests.

Views, taxonomy and queue work

Beyond authenticated traffic, the reliable cost centres are large views with many filters and relationships, which generate expensive joins; deep taxonomy trees, where term hierarchies are traversed on every render; and cron or queue work such as search indexing, feed imports and media derivative generation.

Queue workers should not share the web server’s resources with visitors if you can avoid it. On a larger site they belong on a separate process or instance, so an import backlog cannot make the front end slow. That is an architecture decision made at buying time, and it is the point at which the managed tiers stop fitting and custom infrastructure starts to.

Getting the Decision Right

The pattern is consistent. The hosting is not undersized, it is the wrong shape: no shell, no object cache, an opcode cache someone else controls, and a PHP version about to fall out of support. Moving the same site onto a correctly specified instance at a similar price usually beats any amount of front-end optimisation.

Mecanik specifies, builds and maintains Drupal infrastructure as part of our website development work, and reviews existing stacks through a server security audit when the concern is exposure rather than speed. If you need people rather than a platform, our guide to hiring a Drupal developer covers what to look for.



Frequently Asked Questions

What are the minimum server requirements for Drupal 11? PHP 8.3 or newer, and MariaDB 10.6, MySQL 8.0, PostgreSQL 16 or SQLite 3.45 as the database. Apache 2.4.7 or Nginx 1.1 and later on the web server side, with Microsoft IIS unsupported from Drupal 11.0.0 onwards. Drupal warns below 64MB of PHP memory, but 256MB is the realistic production figure.

Can Drupal run on shared hosting? It will install and it will serve pages, but shared hosting usually fails three or four requirements at once: no shell access for Composer or Drush, a PHP memory limit you cannot raise, no Redis or Memcached, and cron that only fires when a visitor happens to load a page. Those conditions are what produce the reputation for Drupal being slow.

How much should Drupal hosting cost? A small Drupal site on a properly configured unmanaged instance typically sits around GBP 20 to GBP 120 a month before anyone manages it. Managed Drupal platforms commonly start near GBP 40 and rise into the hundreds with traffic and environments. Custom infrastructure starts to make sense above roughly GBP 400. The cheapest tier is rarely the cheapest outcome.

Does Drupal need Redis? Not for a small anonymous site, where the internal page cache and the database are adequate. Once you have logged-in users, editors or a members area, an external object cache such as Redis or Memcached moves cache reads, locks and queues off the database, and it is usually the single largest improvement available for the money.

Is a CDN safe in front of a dynamic Drupal site? Yes, provided you invalidate by cache tag rather than by time. Drupal records tags such as node:5 for everything a response depends on, and modules translate those into Cache-Tag or Surrogate-Key headers so the CDN purges exactly the pages an edit affected. Without tag invalidation you are choosing between stale pages and a cache that never helps.