Skip to content

Your First Site

By the end of this page you’ll have a real blog post rendering on a public URL — and the muscle memory for how Total CMS fits together. About 10 minutes if you have Total CMS installed already; add a few more if you don’t.

If Total CMS isn’t installed yet, follow the Installation guide first. When the wizard asks for a starter pack, the minimal starter is the cleanest base for this tutorial.

Picked a different starter? Not a problem. The blog, business, and portfolio starters already include builder pages and templates — you can still follow along, but consider using a unique URL like /posts in step 4 so it doesn’t collide with what’s already there.

Visit your install URL and log in. You’ll land on the dashboard.

Total CMS admin dashboard

The left sidebar holds your main navigation. Two icons we’ll use today:

  • Collections — your content (blog posts, images, products, anything)
  • Builder — your Site Builder pages (URLs and templates)

A new install doesn’t ship with content collections — you choose what you need. To get the standard ones in a single click, find the Project Setup link on the dashboard and open it.

Click Setup Default Collections. Total CMS creates the standard collections — blog, gallery, image, file, and more — each wired up with the matching schema. This process could take a little while.

Already have collections from a starter pack (blog, business, portfolio)? You can skip this step. The collections you need already exist.

Click Collections in the sidebar. You should now see blog in the list — click into it and hit + New Post button at the top.

Fill in:

FieldValue
TitleHello, Total CMS
SummaryA paragraph or two — whatever you like
ContentA paragraph or two — whatever you like
(rest)Leave the defaults

Click Save (or cmd+S). Your post lands in the collection’s list.

New blog post form

You just created your first object — one record in the blog collection. The fields you filled in (title, content) are the object’s properties, and the shape they conform to (which properties exist, what type each is) is defined by the blog schema.

There is no database. Your blog post is a file. Open tcms-data/blog/ in your code editor and you’ll find a JSON file named after your post’s ID:

{
"id": "hello-total-cms",
"title": "Hello, Total CMS",
"body": "A paragraph or two — whatever you like",
"date": "2026-05-13T14:23:00",
"draft": false
}

This is what we mean by flat-file. Your content lives on disk as JSON — version-controllable, copy-able, scriptable. The admin is just a UI for editing these files.

We have a post; now we need a URL where visitors can see it.

Click Builder in the sidebar and click on the + New Template button. Use the following values:

FieldValue
TypePage
IDposts

Paste this into the code box:

{% extends 'layouts/default.twig' %}
{% block title %}Posts from {{ cms.config('domain') }}{% endblock %}
{% block content %}
<h1>Posts</h1>
{% for post in cms.collection.objects('blog') %}
<article>
<h2>{{ post.title }}</h2>
<p><small>{{ post.date | date('F j, Y') }}</small></p>
<div>{{ post.summary }}</div>
</article>
{% endfor %}
{% endblock %}

Save the template. The admin writes the file to disk for you.

Prefer your own code editor? The template lives on disk at tcms-data/builder/pages/posts.twig. Open it in VS Code, vim, or whatever editor you like — Total CMS picks up changes from either place. The admin editor and the filesystem are the same file.

Now click on the + New Page at the bottom of the nav bar to create a page route for our template.

FieldValue
TitlePosts
URL Path/posts
Page Templatepages/posts.twig

Save it.

Site Builder — new page

The page record now exists in the builder-pages collection (yes, builder pages are themselves objects in a collection). The router will send any request for /posts to the page template that we created pages/posts.

Visit /posts on your install:

Rendered posts page

There’s your blog post, rendered by your template, served by Site Builder.

Add another post in the admin and refresh — it appears at the top of the list without you touching the template. The template is general; the content is data.

In about 10 minutes you used every core piece of Total CMS:

You didWhat it’s called
Ran Project Setup → Setup Default CollectionsCreated the standard collections + their schemas
Added a record in the adminCreated an object in the blog collection
Filled in fieldsSet the object’s properties
Saw the JSON file on diskSaw flat-file storage in action
Created a /posts page in BuilderRouted a URL to a template via the builder-pages collection
Wrote a Twig templateUsed cms.collection.objects() to fetch records and render them

Everything else in Total CMS — custom fields, forms, auth, extensions, APIs — builds on these foundations.

  • Site Builder Overview — page records, routes, templates in depth
  • Twig Overview — the template engine and the cms.* API surface
  • Collections — loading and filtering content in templates
  • Collection Filtering — pagination, sorting, where-clauses for your post list
  • Media — adding images and image variants to your posts
  • Schemas — defining your own collection shapes (products, team members, anything)