Learn how WordPress rewrite rules work under the hood. Discover why calling flush_rewrite_rules too often causes performance issues and how to manage it.
I remember sitting on a support call about three years ago, watching a site’s TTFB climb to nearly two seconds every time an administrator saved a post. It turned out the developer had placed a flush_rewrite_rules() call directly inside a save_post hook. It was a classic mistake: they were essentially rebuilding the entire URL routing table on every single update, causing a massive I/O bottleneck.
If you’re working with custom post types or complex routing, you’ve likely bumped into the WordPress Rewrite API. Understanding how flush_rewrite_rules updates the database and .htaccess is the difference between a snappy site and one that hangs every time a user hits "Update."
When a user visits a URL, WordPress doesn't just "know" where the content lives. It uses a complex set of regular expressions to map that URL to a query. These rules are stored in your database under the rewrite_rules option key.
When you call flush_rewrite_rules(), WordPress performs a heavy lifting operation:
wp_options table.save_mod_rewrite_rules() to update the .htaccess file if you're on Apache.This isn't a lightweight operation. In my experience, on a site with around 500 custom rules, this process can add roughly 200ms to a page load. If you’re doing this on every page view or every post save, you’re hitting the disk and the database hard for no reason.
The .htaccess generation part is where things get tricky. WordPress uses the WP_Rewrite class to generate the rewrite block. If you're on a server where the filesystem is slow or locked, this call can trigger a race condition or a timeout.
We once tried to automate a custom routing system by flushing rules every time a user changed a site setting. It worked for a week until the traffic spiked. The site started throwing 500 errors because the WP_Rewrite object was trying to write to the file system while simultaneously being accessed by hundreds of concurrent requests. We eventually had to move the flush logic to a dedicated CLI command.
If you want to master the full scope of how these requests map to content, check out my guide on the WordPress Rewrite API: How URL Requests Map to Content.
You only need to flush when the routing structure changes. This happens when:
add_rewrite_rule().You do not need to flush just because you updated a post or changed a meta field. If you’re struggling with rules not showing up, you might want to review WordPress Rewrite API: Managing Rules and Flush Failures to see if your registration logic is firing at the right time.
Instead of calling the function blindly, check if you actually need to. You can hook into the activation of your plugin to flush once, rather than on every hook:
PHPregister_activation_hook( __FILE__, 'my_plugin_activation' ); function my_plugin_activation() { #6A9955">// Register your CPTs here my_custom_post_type_registration(); #6A9955">// Flush only on activation flush_rewrite_rules(); }
If you must flush dynamically, use a transient or an option to check if a flush is actually required. Don't let the code run blindly.
Q: Does flush_rewrite_rules() always update .htaccess? A: Only if the filesystem is writable and the site uses Apache. On Nginx, WordPress can't write to the config file, so it relies entirely on the database-stored rewrite rules.
Q: Is it safe to call this in the admin_init hook?
A: No. admin_init fires on every admin page load. You will be flushing the rules thousands of times a day, which is a major performance killer.
Q: What if I have thousands of custom rules?
A: If you have thousands of rules, the rewrite_rules option in the database will grow huge, slowing down every single page load because WordPress autoloads that option. In that case, you should look into using add_rewrite_endpoint() or a custom query var approach to reduce the rule count.
I’m still experimenting with caching the rewrite_rules array in Redis to see if I can bypass the database hit entirely on high-traffic installs. It’s a bit experimental, but for sites with massive rule sets, the standard WP_Rewrite process just isn't built for that kind of scale. Always test your flush logic in a staging environment before pushing to production—you don't want to be the one who breaks the routing for the entire site.
Master the WordPress Rewrite API and learn why calling flush_rewrite_rules incorrectly ruins performance. Get expert tips on managing WordPress permalinks.
Read moreWordPress rewrite rules dictate how your site maps URLs to content. Learn how the WP_Rewrite engine transforms permalinks into regex for efficient routing.