FIELD NOTES / SOFTWARE ARCHITECTURE
Why WordPress migrations fail— and what they taught me about building better software
I spent days trying to move a website. The experience changed how I think about the software behind it.
THE SHORT ANSWER
WordPress migrations can fail when the transfer exceeds server limits or the destination cannot reproduce the site’s dependencies. Copying the files is only part of the job. Runtime compatibility, database values, permissions and infrastructure matter, too.
Years ago, while working at an advertising agency, I worked with a lot of websites built in WordPress and Joomla. One experience in particular stuck with me.
We needed to move an existing WordPress site from one server to another. On paper, that sounded simple enough. Export the site, move the database and files, point the domain to the new server, and move on.
Instead, I spent hours — eventually days — trying different migration tools. Free versions. Paid versions. Different backup methods. Different import methods.
The result was usually the same: the migration failed.
At the time, I mostly saw it as one more reason I didn’t enjoy working with WordPress. Looking back at it now as a software developer, I understand the problem much better.
I can’t identify the exact cause of those failures without the original logs and server configuration. But the experience illustrates a broader problem: a mature WordPress installation can become tightly coupled to the environment it has been running inside for years.
Moving it can mean moving much more than a website.
A WordPress site is more than its pages
When somebody sees a WordPress site, they usually think of the visible website: pages, blog posts, images, menus and contact forms. But underneath that is an entire application environment.
A WordPress installation can depend on:
- Application code: the WordPress core version, plugins, themes and custom PHP.
- Runtime and data: the PHP version, PHP extensions, MySQL or MariaDB, database configuration and uploaded files.
- Server and infrastructure: filesystem permissions, Apache or nginx, rewrite rules such as Apache’s
.htaccess, scheduled tasks, caching layers, security plugins, SSL configuration, DNS and server-specific settings.
That means moving a WordPress site isn’t always equivalent to copying a folder from one machine to another. You’re trying to reproduce an environment.
If that environment was built years ago, modified repeatedly and never properly documented, the migration becomes much harder.
Why migration plugins sometimes fail
WordPress has plenty of migration and backup plugins. Many of them work well, including for large sites when the tool and hosting environment are configured appropriately.
The problem can come when a site has accumulated years of history. A migration plugin may need to package plugins, themes, years of images and PDFs, the database and configuration. Old backups left inside the site can add even more bulk unless they are excluded.
That operation can be surprisingly expensive:
- The server may run out of memory.
- The operation may exceed PHP’s maximum execution time or a web-server timeout.
- The archive may exceed an upload or request-size limit.
- The server may run out of temporary disk space while creating or extracting the backup.
- The destination may not allow the plugin to write or extract the files.
PHP exposes separate controls for resources and uploads; its configuration documentation explains limits such as memory_limit, post_max_size and upload_max_filesize.
Sometimes the migration plugin isn’t really the problem at all. The server is.
The free version vs. paid version trap
I remember trying both free and paid migration tools. It’s easy to assume:
“The free version isn’t working. Maybe the paid version will fix it.”
Sometimes it does. Some paid versions remove limits imposed by the plugin itself or provide different transfer methods and support.
ILLUSTRATIVE EXAMPLE / NOT A SPECIFIC PLUGIN’S CURRENT LIMITS
- Free version
- Migration packages limited to 512 MB
- Paid version
- Larger migration packages allowed
That doesn’t necessarily fix the environment underneath it. A paid migration plugin still can’t automatically solve every memory limit, timeout, exhausted disk, incorrect filesystem ownership, missing PHP extension, database import failure or incompatible PHP version.
Removing a plugin’s limitation doesn’t remove the server’s limitations.
That distinction wasn’t nearly as obvious to me when I was originally dealing with these migrations.
Old PHP versions can create another problem
WordPress has existed for more than two decades. Some production websites have histories stretching back many years.
Consider this hypothetical move:
| Dependency | Old server | New server |
|---|---|---|
| PHP | PHP 7.2 | PHP 8.x |
| Database | Older MariaDB | Newer MariaDB |
| Web server | Apache | nginx |
| Application | WordPress, a custom theme and several plugins | |
The files may transfer perfectly. That doesn’t mean the application will run.
An abandoned plugin may rely on behavior that newer PHP versions no longer support. A custom theme may contain deprecated calls or code that has become incompatible. A plugin might expect an extension installed on the old machine but missing from the new one.
PHP’s PHP 8.0 migration guide documents breaking changes. Deprecation warnings and fatal errors are different problems, but both deserve investigation before a move.
The transfer technically succeeded. The application didn’t.
The database can make things even stranger
WordPress stores a significant amount of configuration in its database. That includes URLs and, depending on the plugins involved, serialized PHP data.
Serialized strings contain both a value and its length in bytes. For plain ASCII text, like these example domains, that matches the number of characters.
SERIALIZED STRING / CORRECT LENGTHS
s:11:"oldsite.com";
s:23:"new-company-website.com";A careless search-and-replace that changes the domain but leaves the old length can damage the serialized value. A normal SQL replacement may not understand that structure.
Serialization-aware tools do. The WP-CLI search-replace command, for example, handles PHP serialized data and offers a dry-run mode to preview changes.
A server move that keeps the same public URLs may not need a domain replacement at all. The changes should follow what actually moved.
This is one of those details that makes a task that appears simple much more complicated underneath.
File permissions can break an otherwise successful move
This becomes especially relevant when websites are hosted on privately managed Linux servers.
Imagine the original server stored WordPress under /home/client/public_html/, with files owned by one Linux user. The new server expects it under /var/www/example/, with the PHP process or web server running under a different account.
You can copy every file correctly and still end up with an application that can’t upload media, write cache files, generate thumbnails or create temporary files. Plugin updates can also fail if the chosen update method lacks the access it needs.
The application exists. The process running it simply doesn’t have permission to use parts of it.
The WordPress file-permissions guide explains why ownership and the hosting setup matter. The goal is appropriate access to the directories that need it, rather than making everything writable.
Private servers add another layer
The agency I worked for used privately managed servers for at least some of its hosting infrastructure. That can provide a lot of flexibility. It can also create institutional knowledge that exists only in someone’s head.
A site might depend on DNS, a reverse proxy or cache, a web server, PHP-FPM, WordPress and a database. Some environments use both nginx and Apache. That’s an example of the layers a migration may involve, not a reconstruction of the agency’s actual setup.
Add SSL certificates, firewall rules, cron jobs and security software, and suddenly “move the website” means recreating an undocumented infrastructure stack.
If the developer responsible for that server left years ago and nobody documented the decisions they made, the next person inherits an archaeological project.
That’s what I didn’t understand at the time. I thought I was failing to migrate a website. I may have been trying to reproduce an environment I hadn’t built and that had never been fully documented.
Why this changed how I think about software
Experiences like that influenced how I think about building software today. I care a lot more about portability.
I want to know:
- What runtime does the application require?
- What database does it use?
- What environment variables are required?
- How is the application built?
- How is it deployed?
- Where does uploaded data live?
- What infrastructure does it depend on?
- Can another developer reproduce the environment?
A modern application might have substantially more custom code than an old WordPress site while still being easier to deploy.
For example, a Java application could document Java 21, a compatible Spring Boot version, a supported MySQL version, required environment variables and a Docker configuration.
Its documented build command might be:
./mvnw clean package
Provide the required configuration. Apply the database migrations. Attach persistent storage where needed. Start the application and verify that it works.
That doesn’t mean modern software never has deployment problems. It absolutely does. A build command or a Docker image alone doesn’t move the database, uploaded files or external services.
The difference is that good architecture tries to make those dependencies explicit. The same discipline can make a WordPress installation easier to move, too.
Convenience today can become complexity tomorrow
WordPress became successful for a good reason. It allows people to create websites quickly, install plugins easily and manage content without writing software from scratch. Those are real advantages.
But convenience has a cost when every new requirement becomes another plugin, another configuration layer and another dependency.
One plugin becomes ten. Ten becomes thirty. A custom theme gets modified. A caching plugin is installed. A security plugin changes rewrite rules. Someone manually modifies .htaccess. Another developer adds custom PHP directly to the theme.
Years later, someone is asked to move the application. Nobody remembers why half of those decisions were made.
This isn’t exclusively a WordPress problem. Any software system can end up this way. The number of plugins alone doesn’t determine reliability; their quality, compatibility, responsibilities and maintenance matter.
WordPress makes adding capabilities easy. It can be just as easy to overlook the application architecture accumulating behind them.
The lesson wasn’t “never use WordPress”
There are plenty of situations where WordPress is a perfectly reasonable choice. A content-driven site with a carefully maintained plugin stack can work extremely well.
The lesson I took from that experience was broader:
Software should be designed with the assumption that someday someone else will need to understand it, move it, repair it or replace it.
That means documenting dependencies. Keeping infrastructure understandable. Avoiding unnecessary complexity. Choosing technology based on the problem instead of simply adding another plugin.
And making sure the application isn’t dependent on one particular server continuing to exist forever.
Years ago, I spent days trying to migrate a WordPress website and couldn’t understand why something that sounded so simple kept failing.
Today, I see migrations as a test of how well we understand the systems we build. They can expose years of hidden technical decisions.
And that’s something I think about every time I build software now.
RENATUS / A PRACTICAL NEXT STEP
Building software that can outlive its original environment
At Renatus, we build websites and custom software with maintainability, portability and clear architecture in mind. That means thinking beyond whether something works today.
We also think about what happens when an application needs to grow, move to a different hosting provider, integrate with another system or be maintained by another developer.
If your website or internal system has become difficult to maintain, migrate or understand, Renatus can help evaluate the architecture and determine a cleaner path forward.
Let’s talk about your systemTechnical references
The examples above illustrate possible failure modes. These official references explain the underlying behavior: