Auto Version CSS and JS Files

Browsers cache all of the various images, scripts, stylesheets, and other content in order to make subsequent page loads faster. This is a fantastic feature that, when used correctly, can make your website's user experience much better. But it can also be problematic.

The cache may be set to a 'timer' to clear on a certain schedule. But this could leave users seeing incorrect versions next time they visit your website. We need a way to ensure the cache lasts as long as it needs to, and immediately is refreshed when a change is made.

File Naming vs Versioning

File Naming

File naming as a method is the process of changing the file name each time you want to bust the cache. One example of this would be a file naming convention such as "filename_month-day-year.filetype". One will quickly realize that this method is very time consuming to maintain, especially on a website where a particular file (such as a css or js file) is updated frequently. This requires the file itself to be renamed as well as wherever the file is imported at or called from.


Versioning as a method is the process of appending a query string including a version number to the file when calling it on the page. Modern browsers have gained this ability that alleviates many of the pains of renaming files or offering the "please clear your cache and perform a hard refresh" solution (if solution is even the correct word for that). Its a fantastic way to ensure the cache can be cleared whenever you want it to, but it seems to remain largely unknown to many web developers I talk to.

Manual Versioning

The first introduction to versioning via query strings I had was a manual process. Manual versioning (increasing the version number manually each time you update the file) is very time consuming and just about as bad as renaming the file each time. The main difference is that the manual update only has to occur wherever you import or call the file rather than renaming the file itself (which proves very problematic in modern frontends using webpack or other compilation forms). That lead me to think, how can this be automated?

Automatic Versioning

Well, it turns out that automatic versioning is very simple and one of those "duh, why didn't I think of that?" type solutions. I'm not the first person to discover it by any means, but it randomly popped into my mind one day and led me to a series of google searches finding others who had discovered it. So, what is this generic "it" that I keep talking about?

Let's think it through for a second. What is unique about a file each time a change is made to it? The "last modified" timestamp! All we have to do is to append the "last modified" timestamp for a file import via a query string. This enables 'auto versioning' in the sense that the version will be updated instantly when the file is modified, but remain the same when it isn't. It's great, right? The beauty of the abstract idea is that it could be easily applied in any language, framework, or CMS. Let's look at a few examples of how to do this with PHP, Laravel, and WordPress.

Automatic File Versioning in PHP

$cssVersion = filemtime('/path/to/file.css');

<link rel="stylesheet" href="<?php echo '/css/file.css?v=' . $cssVersion ?>">

Automatic File Versioning in Laravel

<link rel="stylesheet" href="{{ asset('css/app.css') . '?v=' . filemtime(base_path() . '/public/css/app.css') }}">>

Automatic File Versioning in WordPress

* Get timestamps for style.css, app.js
$style_css_version = filemtime( get_stylesheet_directory().'/style.css' );
define( 'STYLE_CSS_VERSION', $style_css_version );
$app_js_version = filemtime( get_stylesheet_directory() . "/js/app.js" );
define( 'APP_JS_VERSION', $app_js_version );

	get_bloginfo( 'stylesheet_url' ),
	get_bloginfo('template_url') ."/js/app.js",
	true // adds script to footer for non-blocking js load.

One thing to watch out for with some wordpress themes is the ability to remove versioning from script/style enqueues within the functions.php file. If you're having trouble getting the version to work (or even appear on the frontend source code at all) check for something along the lines of the following code that utilizes wordpress filters to remove versioning.

function _remove_script_version( $src ){
   $parts = explode( '?', $src );
   return $parts[0];
add_filter( 'script_loader_src', '_remove_script_version', 15, 1 );
add_filter( 'style_loader_src', '_remove_script_version', 15, 1 );