Guides
Blog
Add a blog with drafts, cover photos, and an admin editor.
Enable the blog
Add Blog under apps in itsy.config.json, keeping your other settings:
{"apps": {"blog": {"mount": "/blog"}}}Current generated sites include the Blog templates. For an older site, copy the Blog templates and styles from a fresh site while preserving your layout:
site/blog/_index.htmland_post.htmlsite/admin/blog.htmlandblog-edit.html- The Blog rules in
site/css/global.css
Restart dev and link to /blog from your navigation.
Write and publish
Run itsy admin admin@example.com to add an admin. Sign in at /admin with the emailed code; enabled Blog sites open /admin/blog. Local dev previews the email; live sign-in needs HTTPS and email delivery. Commit and deploy admin-list changes before sharing live access.
In the Blog admin, choose New post, add a title, slug, excerpt, and body, then save the draft. You can also choose a cover photo.
Publish makes the post public; Unpublish makes it a draft again. Saving a published post updates it immediately. Publication dates control ordering, not scheduled publishing.
Draft text stays private. Uploaded JPEG or PNG cover photos remain public assets, including draft covers. Choose an existing photo or upload one in the post editor; saving the post stores its selected cover. Keep the admin forms, session handling, and CSRF controls intact.
Cover uploads accept JPEG or PNG up to 8 MiB and 20 megapixels. Photos are resized to at most 2048 pixels and embedded metadata is stripped. The library supports up to 100 photos and 64 MiB of files. Ordinary page images and videos stay in site/ as static assets.
Customize the templates
The listing template receives published posts:
{#each blog.data.posts as post}
<article>
<h2><a href="{post.url}">{post.title}</a></h2>
<p>{post.excerpt}</p>
</article>
{/each}The post template receives blog.data.post:
<h1>{blog.data.post.title}</h1>
<div>{blog.data.post.body}</div>The body renders sanitized rich HTML. Keep it in element content, as shown above.
Posts in JSON
Blog storage remains in itsy/snips.json, with top-level blog and media records. Cover files live in itsy/media/. Ordinary pages and their metadata stay in HTML.
Posts live in the blog array. An agent can add a draft like this while preserving the file's other records:
{
"id": "a7Km2pQ9xB",
"title": "Notes from the bookshop",
"slug": "notes-from-the-bookshop",
"excerpt": "What we've been reading.",
"body": "<p>Our latest finds from the shelves.</p>",
"status": "draft"
}Use a unique ten-character alphanumeric ID and keep it stable. Published records also need published_at, such as 2026-11-14T10:00:00Z.
Deploy and sync
The content command below requires Itsy 0.22.0 or newer and matching server protocol 30.
Normal deployment preserves existing live posts and cover photos, and seeds new post IDs. To change an existing live post in source, stop dev and download the destination’s content first:
itsy pullReview and commit the result. After editing and reviewing local posts, publish the content changes with:
itsy deploy --with-contentThe explicit content sync requires a matching pull baseline for an existing destination. Conflicting post changes are compared as whole records and need a choice. Omitting a post from source does not delete it from the live site.
Changing a slug changes its URL. Add a redirect when an old address should keep working.