Why We Store Everything as Flat Files on S3

Most blogging platforms store your content in a database you'll never see. If the service shuts down, your posts go with it. BlogWarp takes a different approach: every piece of your blog — posts, images, rendered pages — lives as plain files on S3-compatible storage.

This isn't a technical curiosity. It's a design philosophy.

Your blog is a folder

When you create a blog on BlogWarp, we create a directory in S3. Here's what it looks like:

tenants/{blogId}/
posts/
media/
comments/
config/
theme/
system/
public/

Seven directories, each with a clear purpose. Let's walk through them.

posts/ — Your writing, in Markdown

Every post is a single .md file with YAML front matter:

posts/01jq7r8k2m4n5p6q7r8s9t0u1v.md

Open it in any text editor and you'll find something like:

---
id: 01jq7r8k2m4n5p6q7r8s9t0u1v
title: "First snow"
slug: first-snow
date: 2025-10-15T22:01:00Z
status: published
format: markdown
tags: ["winter", "travel"]
summary: "A short note about the first snow."
author: "Jean-Yves"
---

The first snow arrived last night...

Standard Markdown. Standard YAML. No proprietary format, no binary blobs, no JSON graph you need a PhD to untangle. You can read, edit, and process these files with any tool that handles text.

Draft posts live in the same posts/ folder — their status field is set to draft instead of published. No separate directory needed.

media/ — Your images and files

Upload a photo, and it lands here as its original format — JPEG stays JPEG, PNG stays PNG. We don't re-encode or lock files behind an API. Download the folder and you have all your images.

comments/ — Reader conversations

Each post with approved comments gets a JSON file:

comments/01jq7r8k2m4n5p6q7r8s9t0u1v.json

{
"post_id": "01jq7r8k2m4n5p6q7r8s9t0u1v",
"comments": [
{
"id": "01jq7s9x...",
"author": "Alice",
"date": "2025-10-15T22:12:00Z",
"body": "Great post!"
}
]
}

Comments live in a database for day-to-day operations (moderation, rendering), but every approved comment is synced to S3 as plain JSON. If you download your blog folder, you get every conversation that ever happened on your site.

config/ — Blog settings

config/about.md

Your About page content, stored as a Markdown file you can edit directly.

theme/ — Your blog's look and feel

theme/
theme.json
templates/
base.html
post.html
index.html
partials/
post-card.html
pagination.html
assets/
styles.css

The complete theme — Liquid templates, CSS, configuration — stored as plain files on S3. This is the source of truth. We also cache theme files in a database for fast rendering, but during a sync, S3 always wins. If you wanted to edit a template by hand and upload it to S3, the next reconciliation would pick it up.

system/ — Indexes and manifests

system/
posts.index.jsonl # Metadata for all published posts
search_index.jsonl # Full-text search data
manifest.json # Complete inventory of every file

These are generated files — rebuilt every time you publish. The posts index powers your blog's listing pages. The search index enables client-side search. The manifest is a complete inventory of every object in your blog directory, useful for syncing and debugging.

None of these are precious. Delete them and the next publish regenerates everything from your posts.

public/ — The rendered site

This is where the magic happens. When you publish a post, BlogWarp renders it to static HTML and writes the result here:

public/
index.html # Homepage
feed.xml # RSS feed
sitemap.xml # For search engines
robots.txt
favicon.ico
about/index.html # About page
archive/index.html # Archive listing
archive/2025/index.html # Yearly archives
tags/winter/index.html # Tag pages
posts/first-snow/index.html # Your post, rendered
posts/first-snow/index.md # Your post, as Markdown
assets/styles.css # Theme CSS (copied from theme/)
assets/avatar.jpg # Your avatar
media/photo.jpg # Public copy of your image

The public/ directory is your website. A CDN serves it directly — no application server needed for readers. Just static files, instantly fast.

Notice that every post is published as both HTML and Markdown. Readers get the rendered page. Anyone who wants the source — or any tool that consumes Markdown — can grab the .md file.

Assets in public/ are copies. The originals live in theme/ and media/. This separation means your rendered site can always be rebuilt from source — if anything goes wrong, a single republish regenerates every page from your Markdown files.

Why this matters

You can leave anytime

Every file in your blog directory is a standard format: Markdown, YAML, HTML, XML, JPEG. There's no export step, no conversion tool, no "please email support to get your data." Your content is already in the most portable formats that exist.

Download your folder. Point another static host at it. You're done.

Your blog survives us

If BlogWarp disappeared tomorrow, your S3 bucket would still be there. The public/ directory is a complete, working static website. Upload it to any web host — Netlify, GitHub Pages, even another S3 bucket with static hosting enabled — and your blog is live again, with no changes.

This isn't a theoretical promise. It's an architectural guarantee. We don't hold your content hostage because we literally can't — it was never in a format only we could read.

The database is optional

BlogWarp uses a database to index your posts for fast queries in the admin UI. But the database is a cache, not the source of truth. Every post, every image, every rendered page exists on S3 first. If the database disappeared, we could rebuild the index from your files.

This is the opposite of how most platforms work. Usually the database is the content, and exports are an afterthought. We inverted that relationship.

Simplicity compounds

Flat files are easy to reason about. Need to debug a rendering issue? Read the .md file. Want to bulk-edit tags? Script it with any language that reads YAML. Need a backup? aws s3 sync. Want to migrate? Copy the folder.

Every decision we avoided — custom binary formats, proprietary databases, opaque content graphs — is a decision you'll never have to work around.

What we don't store on S3

The only things that live exclusively in a database are application state: user accounts, sessions, moderation queues. These aren't your content — they're ours.

Everything else — posts, media, comments, themes, indexes — has a canonical copy on S3. We also keep copies in a database for fast queries and rendering, but the database is a cache. S3 is the source of truth. During reconciliation, if a file on S3 differs from what's in the database, S3 wins.

Bring your own bucket

For advanced users, BlogWarp supports connecting your own S3 bucket. Your blog files live in your AWS account, under your IAM controls. BlogWarp just needs write access to render and publish.

The directory layout stays the same:

blogs/{blogId}/
posts/
media/
comments/
config/
theme/
system/
public/

Same files, same formats. Your bucket, your rules.

The bet we're making

We're betting that the value of a blogging platform isn't in trapping your content — it's in making it effortless to write, publish, and maintain a blog. The writing experience, the themes, the CDN delivery, the one-click publishing — that's what you're paying for.

Your words, your images, your blog? Those were always yours. We just made sure the file formats agree.