Skip to main content

Scratch your own itches

The best way to complain is to make things.

— James Murphy

The website you’re currently visiting can be best described as a “blog”.

But under the hood, it’s a full fledged Django web application with database models, REST APIs, an internal admin website and more. Is it overkill?

Blogging vs. blog setups

(Source: Honestly Undefined)

I’m sure this chart resonates with many. From my own experience browsing the web for more than twenty years, I can say it’s accurate: the overwhelming majority of content online is served by arcane technologies such as WordPress or “raw HTML,” and many people who boast their advanced blogging setups rarely publish anything at all. (Myself included, as of writing this post.)

Why is this the case?

Everyone will have different answers, but as someone who has written their own CMS, I can tell you my own.

WordPress

WordPress is an incredibly successful piece of software. It is the most deployed blogging solution worldwide, and it has decades of craft and expertise dedicated to it.

Among all the incarnations of my personal website, WordPress was my second favorite to work with. I was able to build new features quickly and with ease.

The biggest problem I had with WordPress was the ecosystem. Any shortcomings of WordPress can be addressed through themes and plugins. And everyone is trying to sell you something. I can see why, because the target audience for WordPress consists of:

  1. Agencies who build websites for others, meaning any expenses for the WordPress ecosystem can be billed to customers
  2. People who have little to no experience with programming, whose best option in the ecosystem is a paid solution

I belong to neither category. When I am faced with a third-party solution to even the most basic problem I’m having, my reaction is overwhelmingly negative.

Examples:

  1. It’s not trivial to set up a Git repository structure for a WordPress project. The best solution is Bedrock.
  2. It’s not trivial to set up Composer to work well with WordPress. Again, the solution is Bedrock.
  3. The “default” path to deploying a WordPress site is transferring your source code to the remote host (via FTP or rsync). Many alternatives exist, but I chose Trellis in the past, and my ops turned into an over-engineered mess.
  4. Your content is sometimes not a post? You basically have to use Advanced Custom Fields.

These are not niche requirements for super-specific projects. In today’s web development landscape, these capabilities are regarded as the bare minimum.

Despite all this, I was able to build something that I was happy with in a short amount of time. I was writing my first post with the working title “Proudly powered by WordPress” – praising the “tools don’t matter” ethos and chronicling how WordPress was a historically significant piece of software that helped millions to publish.

Then the drama happened, and I decided that tools do matter. Not wanting to associate myself with Matt Mullenweg is a reason good enough to ditch a tool for me.

Astro

My website is not a static site. Sure, you could implement it as one, but I’ve decided in advance that I want this site to be dynamic. Fortunately, the tooling for building hybrid sites (part static, part dynamic) is great.

Enter Astro.

Astro is great, because unlike similar frameworks like Next.js or Gatsby (both of which I’ve used in the past for building my blog) it’s not tightly coupled to React (yuck). Components are easy to write, styling is a breeze.

Regardless of the chosen frontend framework, I needed a CMS. You can use Astro without a CMS if all your content can live in a version controlled filesystem hierarchy, but I needed a relational database.

Astro ships their own database integration, but the docs read almost like a paid partnership with Turso to get you to rent their services. Again, this seemed to me as if someone was trying to sell me something.1

I spent a long time looking for a suitable CMS for the project. Astro’s documentation on CMS integrations offered many alternatives. My requirements are:

  • Free (this is a hobby project, and I don’t want to spend any money on top of hosting)
  • Self-hosted
  • Ability to offload assets to S3 or elsewhere
  • Headless
  • Easy to extend if needed

For example, I’ve extended WordPress to extract EXIF tags from uploaded images and display them on photo posts, like in this post.

I’m sure tools like Strapi, Kirby or Payload would have been adequate. They all advertise themselves as catered to developer types, having “code-first” approaches as opposed to “click ops”.

Sounds good, but do I really want to build my website on SaaS products meant for enterprises?

For perfectionists with deadlines: Django

My needs are much simpler. To me, spinning up a new Django app is much more straightforward:

class Post(models.Model):
    title = models.CharField(max_length=200)
    created = models.DateTimeField(default=timezone.now)
    modified = models.DateTimeField(auto_now=True)
    slug = models.SlugField()
    summary = models.TextField(null=True, blank=True)
    body = models.TextField()
    tags = models.ManyToManyField(Tag, blank=True, related_name="posts")
    categories = models.ManyToManyField(Category, blank=True, related_name="posts")
    is_draft = models.BooleanField(
        default=False,
        help_text="Draft entries do not show in index pages but can be visited directly if you know the URL.",
    )

Initially I served these kinds of CMS objects using a REST API, powered by Django Ninja. Astro would then consume this API to generate pages either at build time or when handling a request.

Serving pages rendered on-demand with Astro requires you to configure a server adapter. There are four adapters: Vercel, Netlify, Cloudflare and the only self-hosted option: Node. The rest are commercial services.

I’m not denying that these popular hosting providers add significant value. They offer a generous free tier and have a straightforward workflow. However, they are all serverless cloud providers, and that’s where my issues start. I find it difficult to intuitively grasp their usage metering and pricing structures. Again, the feeling of someone trying to sell me something.

Actually, scrap all that–if I end up using Django to build a CMS, why wouldn’t I render HTML pages directly from there?

def post(request, year, slug):
    post = get_object_or_404(Post, created__year=year, slug=slug)
    return render(request, "blog/post.html", {"post": post})

Add a few more models, a few more views, Bob’s your uncle, you have this website.

Itches

I anticipate that many of the gripes I’ve listed until now are not concerns for many. That’s okay! These are specifically my itches.

I like having the flexibility of having server-side rendering and a full-fledged web framework at hand.

I like to work in an ecosystem where I’m not constantly being sold something.

In the end, I am a tech enthusiast—building something and understanding it down to its deepest details is part of the allure of creating a personal website. A blog powered by Django is more similar to a WordPress setup than most would think—you only have to create the Post model yourself.

I used Django in my first software engineering job. Django took us from startup scale to IPO. I should also give credit to Simon Willison, co-creator of Django, for inspiring me to build my own site using Django.

Further reading

“Scratch your own itch” on the IndieWeb Wiki

Footnotes

  1. I’m aware that you can use any libSQL compatible database, which you can self host. I should stress, this is how I perceive what I’m presented with when trying to solve a problem, looking at their documentation. 

Back to the home page