Baking a Static Site from Wagtail CMS

Note: This site is no longer built with the technique described below.

I've struggled to settle on a tech stack for this site, but I finally have a great solution with the best of two worlds: an open-source, free, full-featured CMS with all the builtins of Django, and the performance and operational ease of a static site.


The Summary

Walkthrough

Django and Wagtail

Because we're going to run Django and Wagtail on our local machine, and not a server exposed to the Internet, a basic "getting started" tutorial that ignores security, deployment, and performance is sufficient. For Wagtail, it's here.

As you'll read, it's little more than this to get started:

$ echo 'make a virtual environment and activate it'
$ virtualenv myvenv
$ . myvenv/bin/activate

$ echo 'make the Wagtail site'
$ pip install wagtail
$ wagtail start mysite
$ pip install -r requirements.txt
$ ./manage.py migrate
$ ./manage.py createsuperuser
$ ./manage.py runserver
Starting development server at http://127.0.0.1:8000/

We never have to configure Django with production-quality settings or run a WSGI server like Gunicorn: the development server is all we need. By default all site content is persisted in a SQLite file, which is a great choice for our use case.

Follow the comprehensive Wagtail docs, write your models and templates, and then browse to 127.0.0.1:8000/admin to access the content editor's interface. If you're making a blog or other site that requires freeform content, you will want Wagtail's StreamField.

Baking the Static Site

Wagtail-bakery is a Wagtail-specific version of Django-bakery that works almost out-of-the-box perfectly to export a Wagtail site as static files. Thank you, open-source maintainers!

Wagtail-bakery's README gives a great walkthrough, and that is all you should need. The simplest config looks like this:

# settings.py
INSTALLED_APPS = [
    # your homemade apps here
    # ...
    "bakery",
    "wagtailbakery",
    # other 3rd party apps here
    # ...
]

# other settings
# ...

BUILD_DIR = os.path.join(BASE_DIR, "build")
BAKERY_VIEWS = ("wagtailbakery.views.AllPublishedPagesView",)

It registers some Django management commands for you, one of which builds the site:

$ ./manage.py build
Build started
Build finished
$ echo 'tree -L 1 prints the file system hierarchy up to 1 level deep'
$ tree -L 1 build/
build/
├── blog
├── index.html
├── media
└── static

Deploy to Netlify (or S3, or anywhere else)

Even with Netlify, it takes some know-how to deploy a site. You'll probably want a custom domain name, and then you should want to point your domain's DNS records at your Netlify URL (using CNAMEs) or associate your domain with Netlify nameservers. Netlify has good docs on this and other topics.

In the end, you will want to tell the Netlify CLI that your site is in the /public directory:

# netlify.toml
[build]
publish = "build/"

Then deployment is as simple as:

$ netlify deploy

Congratulations

Now stop fiddling with your blog and write something!