How-to: a blog
The blog is what septic is for: posts live in a database, and septic build turns the published ones into a static site via poops. One config; drafts never ship.
The backend half. You end with posts in a database and a built site. Writing them from an admin page served beside that site is laxative's version of this how-to.
1. The posts resource
{
"septic": {
"db": "data/blog.db",
"auth": { "seed": { "email": "you@example.com", "password": "changeme", "role": "admin" } },
"resources": {
"posts": {
"methods": ["GET", "POST", "PUT", "DELETE"],
"access": { "read": "public", "write": "admin" },
"fields": {
"title": "string required",
"slug": "slug required unique",
"body": "text required",
"excerpt": "text",
"status": "enum(draft,published) = draft",
"published_at": "datetime",
"created": "datetime = now",
"updated": "datetime = now!"
}
}
}
}
}
2. Wire the bridge โ published only
"build": {
"resources": {
"posts": {
"into": "src/markup/posts",
"slug": "slug",
"body": "body",
"layout": "post.html",
"where": { "status": "published" }
}
}
}
where is the important bit: septic build emits only published rows, so drafts stay out of the static site. Each post becomes src/markup/posts/<slug>.md โ YAML front matter (title, excerpt, published_at, โฆ) + the body โ kept in step each build (only changed files rewritten, deleted rows swept), then poops compiles the site.
3. Write a post
npx septic serve
# log in
curl -c jar -X POST localhost:3000/api/_auth/login \
-H 'content-type: application/json' -d '{"email":"you@example.com","password":"changeme"}'
# publish one
curl -b jar -X POST localhost:3000/api/posts -H 'content-type: application/json' \
-d '{"title":"Hello","slug":"hello","body":"# Hi\n\nFirst post.","status":"published","published_at":"2026-08-05 12:00:00"}'
4. Build the static site
npx septic build # published posts โ src/markup/posts/*.md โ poops โ dist/
A post.html layout renders each post; a posts/index.html lists the collection โ that part is poops, the static-site generator. A minimal layout:
<!-- post.html -->
<article>
<h1>{{ page.title }}</h1>
<time>{{ page.published_at }}</time>
{{ content }}
</article>
5. Author from a form (optional)
Add build.forms for a write/edit form:
"build": { "forms": { "posts": { "into": "src/markup/_partials", "submitLabel": "Publish" } } }
GET /api/posts/:id as an admin wanting HTML returns a prefilled edit form (PUT). See Forms.
What you got
Posts in a database โ a static blog, drafts excluded, from one config. For the full app โ an admin page to write posts, served next to the site โ see the same how-to in laxative.