Caching is better with hashing

Make your website fast and keep your deploys snappy

cdnupload uploads your website’s static files to a CDN with a content-based hash in the filenames, giving great caching while avoiding versioning issues.

  • Fast and simple to integrate
  • Helps you follow web best practices: use a CDN, good Cache-Control headers, versioned filenames
  • Works with web apps written in any language
  • Written in Python (runs on Python 2 and 3)

The tool helps you follow performance best practices by including a content-based hash in each asset filename.

Deploying is really fast too: only files that have actually changed will be uploaded (with a new hash).

cdnupload is free for fully open source websites, and two commercial license options are available with support plans. See licenses and pricing.

Trivial to install

$ pip install cdnupload

Simple to use

$ cdnupload /site/statics s3://statics-bucket
uploading script.js to script_8f3283c6342816f7.js
uploading style.css to style_abcdef0123456789.css
writing key map JSON to statics.json

Easy to integrate (in most languages)

import json, settings

def init_server():
    with open('statics.json') as f:
        settings.statics = json.load(f)

def static_url(path):
    return '//' + settings.statics[path]

Getting started

To get stuck straight in, choose a license below, then install cdnupload from PyPI using pip install cdnupload. You’ll need to do two basic things:

Integrate cdnupload with your web server. This is so that it knows how to output static URLs with the correct content hashes in asset filenames. For example, you might call the static_url function shown above in your HTML templates like this (Jinja2 example):

<link rel="stylesheet"
      href="{{ 'style.css'|static_url }}">

This will output a link to the CSS with the current content hash in the filename, eg: style_abcdef0123456789.css.

If you have asset URLs in your CSS, for example for background images, use a tool like PostCSS.

Add the upload step to your deployment process. This makes the static files available to users immediately whent the deployment is live. Use the cdnupload command line to control what files are uploaded and where they go (a directory for serving via nginx or Apache, or Amazon S3). This can be as simple as:

cdnupload /site/statics s3://statics-bucket

Generally you’ll want a CDN in front of the file or S3 origin server, but this is not a requirement.

There are a lot of customization options available for more advanced scenarios — see documentation for more info.

Why should I use a CDN?

Diagram of a CDN
Without a CDN, and with one

If you’re not sure what a CDN is, or if you’re wondering why you should use one, this section is for you.

CDN stands for Content Delivery Network, which is a service that serves your static files — heavily cached, on servers around the world that are close to your users.

So if someone from New Jersey requests, the CDN will almost certainly have a cached version in an East Coast or even a local New Jersey data center, and will serve that up to the user faster than you can say “HTTP/2”.

If the CDN doesn’t have a cached version of the file, it will in turn request it from the origin server (where the files are hosted). If you’re using something like Amazon S3 as your origin server, that request will be quick too, and user will still get the file in good time. From then on, the CDN will serve the cached version.

Because the files are heavily cached (ideally with long expiry ties), you need to include version numbers in the filenames. cdnupload does this by appending to the filename a 16-character hash based on the file’s contents. For example, style.css might become style_abcdef0123456789.css, and then style_a0b1c2d3e4f56789.css in the next revision.

On one website we run, we saw our static file load time drop from 1500 ms to 220 ms when we starting using cdnupload with the Amazon Cloudfront CDN.

So you should use a CDN if your site gets a good amount of traffic, and you need good performance from various locations around the world. You probably don’t need to use a CDN if you have a small personal site.

Using the Amazon CloudFront CDN together with Amazon S3 as an origin server is a great place to start — like other AWS products, you only pay for the bytes you use, and there’s no montly fee.


cdnupload is distributed under multiple licenses with a simple model: if you’re giving code away, I’ll give code away. In other words, if your website or web app is open source, you can use cdnupload freely under the AGPL license.

But if you’re a business making a profit, I am too. Specifically, if your website or web app is not open source, you need to use cdnupload under one of the commercial licenses. Pricing is for life, so it’s a one-time fee, including all bugfixes and new features.

Both commercial licenses include several months of fast-turnaround email support, helpful as you integrate cdnupload into your web application.

“But can’t I just download it straight from GitHub or PyPI?” Sure you can. But you’ll be depriving my kids of bread and water me and my wife of dinner dates. And more importantly, I won’t be able to fix bugs or add features as quickly, and you won’t get commercial support. Read more about the author here.

Pragmatically speaking: will using cdnupload speed up your website and save your team a couple of hours of dev time? Then do the right thing, and you’ll get a return on your investment pretty quickly!