How We Built It, Part 0: Why This Stack

The Chattanooga.Digital homepage — the Gig City "Take control of your tech. Go open!" hero, the site this series builds.

This is the start of a series on exactly how Chattanooga.Digital was built — start to finish, with the real commands, the real recipe files, and the real trade-offs. The goal is that by the end you could rebuild a site like this one yourself, or fork ours and make it your own. We are, quite literally, giving away the recipes.

Before any code, this first post answers the question people ask first: why this stack? Three choices shaped everything that follows.

Why a CMS, not a framework

You can build a website by writing application code from scratch (a framework like Laravel, Rails, or Next.js) or by configuring a content management system (a CMS like Drupal or WordPress). The difference matters more than it sounds.

A framework hands you a blank page and a toolbox. Total control, and total responsibility — you build the content editing, the user accounts, the media library, the access rules, all of it. A CMS hands you a running site with all of that already built, and your job becomes modeling your content and arranging it. For a community organization that needs members, events, programs, and a blog — not a bespoke application — the CMS gets you to "useful" in days instead of months, and a non-developer can run it afterward.

Why Drupal, not WordPress

This is the choice with the most depth, and it comes down to how each system stores your content.

Picture how WordPress thinks about a piece of content. Almost everything is a "post" — a single big blob of HTML in one column, plus a bag of loosely-attached key/value metadata. It is wonderfully simple to start, and it works great for, well, posts. But the moment your content has structure — an event that has a start time, an end time, a location, and a recurrence rule; a member who has skills and interests; a program that links to its facilitators — you are stuffing structured data into an unstructured blob, or reaching for a pile of plugins that each invent their own way to fake structure.

Drupal thinks about content the opposite way. The core idea is the entity: a typed thing with typed fields. An "event" is its own content type with a real date field, a real location field, a real recurrence field. A "member" is an entity with real skills and interests fields. Because the fields are real and typed, Drupal can do things with them — sort events by date, filter members by skill, render a calendar, generate an iCal feed — without a plugin guessing at your intent.

The one-line version: WordPress stores content as a blob with metadata bolted on; Drupal stores content as entities with typed fields. For a site that is mostly articles, the blob is fine. For a site that is members + events + programs with relationships between them — which is exactly Chattanooga.Digital — the entity model is the difference between "fighting the tool" and "the tool doing the work for you."

Three honest caveats, because tribalism helps no one:

  • WordPress's simplicity is a real strength for simple sites, and its ecosystem is enormous.
  • Drupal's power comes with a steeper learning curve — the rest of this series is partly about flattening that curve.
  • You can add structure to WordPress (custom post types, ACF). The difference is that in Drupal, structure is the default and the foundation, not an add-on.

Why Docker and Recipes, not click-ops

The last choice is about how we build, not what. We do not build this site by logging into an admin screen and clicking until it looks right. We build it two disciplined ways:

  • Docker gives every developer (and the production server) the exact same environment — the same PHP, the same database, the same web server — defined in a file and started with one command. No "works on my machine."
  • Drupal Recipes capture the site's structure — its content types, fields, views, menus, pages — as version-controlled YAML files. The site can be rebuilt from scratch, identically, from git. The configuration is code you can review, diff, and roll back.

Together these mean the whole site is reproducible: clone the repository, run a couple of commands, and you have Chattanooga.Digital running on your laptop. That reproducibility is the thing that makes a tutorial series like this one even possible — every post points at real files you can run.

What's next

Enough philosophy. In Part 1 we install the whole site on your own machine with Docker and watch it come up at localhost:8081 — the foundation everything else builds on.

Part 1: Install It in Docker →

Beta-test this post with your AI

This series is open-source documentation, and documentation drifts. Help us keep it honest: point your AI coding assistant (Cursor, Claude Code, or similar) at this post and the repo, and if it finds something that no longer matches the code, open a ticket. First time? Read A Token Is an Identity (in this series) so your AI opens issues as you, with credit. Edit the three variables at the top of the block below, then paste it into your assistant:

# ─────── EDIT THESE FIRST ───────
GITHUB_USERNAME = "your-github-username"   # your handle, so the issue is credited to YOU (see the Token Is an Identity post)
DEMO_REPO       = "TortoiseWolfe/gig-city-drupal"   # the repo to file against — or your own fork: GITHUB_USERNAME/gig-city-drupal
ARTICLE_URL     = "https://www.chattanooga.digital/blog/2026-06/how-we-built-it-part-0-why-stack"
# ────────────────────────────────

Read ARTICLE_URL, then clone DEMO_REPO into my local environment and explore it.

Cross-check Part 0 (Why This Stack) against the actual code — the CMS-vs-framework and Drupal-vs-WordPress reasoning, and the "reproducible from a recipe" claim.

If anything is inaccurate, out of date, or contradicts the code, open an issue on
DEMO_REPO (authenticated as GITHUB_USERNAME) so the maintainers can fix the tutorial.

A good issue:
  - one problem per issue (not a catch-all list)
  - a clear title naming the section, e.g. "Part N:  no longer matches the code"
  - cite the exact spot: the post section + the repo file/path (and line if you can)
  - say what the post claims vs. what the code actually does
  - suggest the fix if it's obvious

More insights

Want updates from Chattanooga.Digital?

Pre-join the co-op to receive new posts, workshop schedules, and member updates.