Learn to build Aether CMS themes with custom pages, menus, and pagination.
Intro
I've released today (2025-06-06)
Aether CMS which is a modern and flexible
Node.js content management system with an integrated - ultra fast - static site
generator.
While I've created a detailed documentation for Aether - covering every
aspect of its functionalities (including theming) - my decade of experience in theming tells
me that even if the system is easy with an in-depth documentation, it's not directly
obvious (even for developers) how things work together.
The purpose of this tutorial is
to simplify
Aether theming's documentation
by offering a clearer, step-by-step approach to creating a theme using a real-world example.
Theme Structure
A theme in Aether consists of 3 required files:
theme.json
β The configuration file for your Aether themetemplates/layout.html
β The main template for your siteassets/css/style.css
β The main stylesheet for your theme
Assuming you're building a landing page for a new product, a registration page for an event, a long-form sales page, a mobile app promo with store links, or even a simple 'coming soon' page, the basic structure of your Aether theme would look like this:
π my-aether-theme/
βββ π assets/
β βββ π css/
β βββ π¨ style.css
βββ π templates/
β βββ π§© layout.html
βββ π οΈ theme.json
Theme JSON File
The theme.json
file of your Aether theme is where you define the configuration
fields for it. For brevity I'll only use the
required fields for an Aether theme. Create a theme.json
file at the root of my-aether-theme
and
populate it with the following data:
{
"title": "Clean Blog",
"description": "Clean and responsive, with a clear typography, perfect for personal blogs",
"version": "1.0.0",
"author": "YOUR-NAME-HERE",
"authorUrl": "",
"tags": ["blog", "modern", "responsive", "simple", "clean"],
"license": "GPL-3.0-or-later",
"features": [
"Responsive design",
"One Column",
"SEO optimized",
"Social media integration",
"Featured Images",
"Custom Pages"
],
"screenshot": ""
}
These fields are required for the system to allow the theme upload. As you've noticed,
authorUrl
and screenshot
are provided with an empty-string
(""
); you can do the same for tags
and
features
with an empty-array ([]
).
The only field you cannot
change is license
, its value must be exactly
"GPL-3.0-or-later"
.
Main Template
The layout.html
file is the main template for your site, it must be located
inside a templates folder at the root of your theme directory (e.g.,
my-aether-theme/templates/layout.html).
Main Stylesheet
The style.css
file is the main stylesheet for your site. This file must be
located inside a css folder, which is within an
assets folder at the root of your theme directory (e.g.,
my-aether-theme/assets/css/style.css).
Templating
Templating is the process of getting data from the backend and displaying it in a template
the way we want.
In Aether, a template is just an HTML file β the backbone of the web β
with a .html
extension (e.g., layout.html).
Aether
provides a variety of variables you can use in a theme template, depending on the
context.
In this tutorial, we're going to recreate the
Clean Blog theme by
Start Bootstrap as an Aether theme.
The most
important aspect of templating is understanding the structure of the theme you want to
create. This makes it easier to break the theme into reusable parts and components,
following the
DRY principle (Don't
Repeat Yourself).
Clean Blog Structure
By looking at the Clean Blog preview, we can see that the homepage consists of the following parts:
- A logo with a navigation menu at the top
- A hero section with a background image and some text
- A content section listing posts with navigation
- A footer with social media links and copyright information
After exploring the available links in the themeβs menu, we can see that the
post sample
features a background image that fills the height of the screen followed by its content. In
contrast, the
about
and
contact
pages display their own content.
To summarize this quick overview: the post sample page
stands out with a slightly different structure, mainly due to its taller background image
and unique layout compared to the other pages.
Install Aether
To follow along with creating Clean Blog as an Aether theme, I recommend installing Aether
and working alongside me. This way, you can better grasp the concepts and see how everything
comes together visually in your browser.
I'll assume you have Node.js and npm
installed on your machine. Make sure your Node.js version is at least 18;
if not, you can update by installing the latest LTS (Long Term Support) version from the
official Node.js download page.
To install
Aether, choose a location on your machine where you prefer to work (e.g., in a
tests folder) and open it in your code editor (I use VS Code). Then, in the
terminal, run the following command:
npx create-aether-cms my-cms-site
This will create a ready-to-use version of Aether in a folder named
my-cms-site.
During the installation process, the terminal will output
the following logs until it finishes:
$ npx create-aether-cms my-cms-site
π³ Creating a new Aether CMS project in my-cms-site...
Cloning into 'D:\tests\my-cms-site'...
remote: Enumerating objects: 240, done.
remote: Counting objects: 100% (240/240), done.
remote: Compressing objects: 100% (212/212), done.
remote: Total 240 (delta 19), reused 240 (delta 19), pack-reused 0 (from 0)
Receiving objects: 100% (240/240), 467.82 KiB | 680.00 KiB/s, done.
Resolving deltas: 100% (19/19), done.
π Created .env file with default settings
π¦ Updated package.json with your project details
π Created default content structure
π¦ Installing dependencies (this might take a few minutes)...
added 7 packages, and audited 8 packages in 2s
found 0 vulnerabilities
π Setting up git repository...
β
Renamed origin remote to upstream
Do you want to set up a new git origin for your project? (y/n): n
π Git repository configured with update capabilities
π Success! Created my-cms-site at D:\tests\my-cms-site
π Get started with the following commands:
cd my-cms-site
npm start
π Default admin credentials:
Username: admin
Password: admin
π For documentation, visit: https://aether-cms.pages.dev/
During the installation process, you'll be asked whether you want to connect your Aether installation to a remote Git repository. If you choose not to, the installation will still work locally, and you can always set the Git origin later using:
git remote add origin <your-repo-url>
With Aether set up, letβs get to work and start recreating Clean Blog for Aether!
Clean Blog Creation
If you've already created your Aether theme structure as described above, just rename
the root folder from my-aether-theme to clean-blog. This
helps keep things tidy and follows a logical convention, since the title specified in the
theme.json
file is "title": "Clean Blog"
.
Copy the clean-blog folder into my-cms-site/content/themes
.
Your content folder structure should now look like this:
π content/
βββ π cache/
βββ π data/
βββ π themes/
β βββ π clean-blog/
β β βββ π assets/
β β β βββ π css/
β β β βββ π¨ style.css
β β βββ π templates/
β β β βββ π§© layout.html
β β βββ π οΈ theme.json
β βββ π default/
βββ π uploads/
Starting Aether
If you're comfortable using the terminal, you can navigate into the folder and start the project by running:
cd my-cms-site
npm start
Otherwise, open my-cms-site with your code editor, open a terminal from there, and run:
npm start
The terminal will output something like this:
$ npm start
> aether-cms@1.0.0 start
> node index.js
Creating default admin user...
Default admin user created. Username: admin, Password: admin
You have the latest version of litenode
App @ http://localhost:8080
You can now open http://localhost:8080 in your browser, or simply click the link in the terminal output. Youβll be presented with the default Aether theme.
localhost
refers to your own computer, it's a way to
access the site you're running locally, just for you. The number 8080 is the port it's
running on.
The Administration
To access the Aether administration dashboard, navigate to http://localhost:8080/aether and log in using the default admin credentials:
- Username: admin
- Password: admin
In the Aether dashboard, click the Themes link in the left sidebar. You will be redirected to the Themes Management page. Click on the Clean Blog theme card, and the Theme Details sidebar will appear on the right side of your screen, displaying its information.
Next, click the Activate Theme button. A toast notification will confirm that the theme has been successfully activated, and the page will refresh. Finally, click the View Site button at the top of the Aether dashboard. A new tab will open with a blank page.
Congratulations! Youβve just created the base for an Aether theme.
Clean Blog Index
As seen previously, the Clean Blog homepage displays a list of posts. We have access to
Clean Blogβs source code in its
GitHub repository.
Navigate to the
dist
folder and copy the contents of
index.html
into the content/themes/clean-blog/templates/layout.html
file. Now, refresh the
blank page tab, and the HTML from layout.html
will be rendered.
Next, do the same with
styles.css
by copying its contents into
content/themes/clean-blog/assets/css/style.css
. If you refresh the browser, you
wonβt see any changes yet, because the stylesheet link doesnβt point to the correct path. To
fix this, update the link in layout.html
as follows:
<!-- Find this line -->
<link href="css/styles.css" rel="stylesheet" />
<!-- Replace it with -->
<link href="/content/themes/clean-blog/assets/css/style.css" rel="stylesheet" />
Finally, to get the
scripts
working locally, create a js folder inside the
assets directory. Then create a new file named main.js
and
copy the scriptβs contents into it. Update the script path in
layout.html
like this:
<!-- Find this line -->
<script src="js/scripts.js"></script>
<!-- Replace it with -->
<script src="/content/themes/clean-blog/assets/js/main.js"></script>
Reload the browser. Abracadabra! Youβve successfully replicated the Clean Blog homepage.
Your
clean-blog folder should now look like this:
π clean-blog/
βββ π assets/
β βββ π css/
β β βββ π¨ style.css
β βββ π js/
β βββ π main.js
βββ π templates/
β βββ π§© layout.html
βββ π οΈ theme.json
In Aether, static assets like CSS and JavaScript are loaded using
absolute paths (e.g.
/content/themes/clean-blog/assets/...
) from the theme's
assets folder. You can also organize third-party libraries by placing them
in a vendors folder within assets for easy access and
cleaner structure.
Dynamic Rendering
Replicating the Clean Blog homepage was easy and straightforward, just as Aether is designed to be.
Now comes the fun part, where you'll step into the role of an architect: breaking down the structure into reusable parts and components, then dynamically combining them using modern tools like LiteNode, the core of Aether. It provides everything you need without relying on any third-party libraries whatsoever!
Create 3 new folders within clean-blog:
-
partials - contains the main building blocks of the theme (e.g.
head
,footer
, etc.) - contents β holds the rendering logic for page content based on its context
-
custom - holds the rendering logic for
custom pages
(e.g.
blog
,search
, etc.)
As discussed previously, understanding the structure is a crucial aspect of templating. While we already understood the structure of Clean Blog, we now need to scan its HTML and identify the differences we previously noticed visually. Iβll simplify this task and point out the key differences.
1. The Header of Posts
<!-- The header for the homepage has this structure -->
<header class="masthead" style="background-image: url('assets/img/home-bg.jpg')">
...
<div class="site-heading">
<h1>Clean Blog</h1>
<span class="subheading">A Blog Theme by Start Bootstrap</span>
</div>
...
</header>
<!-- The header for all pages has this structure -->
<header class="masthead" style="background-image: url('assets/img/home-bg.jpg')">
...
<div class="page-heading">
<h1>About Me</h1>
<span class="subheading">This is what I do.</span>
</div>
...
</header>
<!-- The header for individual posts has this structure -->
<header class="masthead" style="background-image: url('assets/img/post-bg.jpg')">
...
<div class="post-heading">
<h1>Man must explore, and this is exploration at its greatest</h1>
<h2 class="subheading">Problems look mighty small from 150 miles up</h2>
<span class="meta">
Posted by
<a href="#!">Start Bootstrap</a>
on August 24, 2023
</span>
</div>
...
</header>
The differences here are:
-
The homepage header uses a
<div>
with the classsite-heading
. -
The page header uses a
<div>
with the classpage-heading
. -
The post header uses a
<div>
with the classpost-heading
. -
The post subtitle uses an
<h2>
tag instead of a<span>
. -
Post metadata such as author and date is included in a
<span class="meta">
.
2. Main Content Wrappers by Content Type
<!-- 1. Index content -->
<div class="container px-4 px-lg-5">
...
<!-- Posts listing -->
</div>
<!-- 2. Page content -->
<main class="mb-4">
<div class="container px-4 px-lg-5">
...
<!-- Content of the page -->
</div>
</main>
<!-- 3. Post content -->
<article class="mb-4">
<div class="container px-4 px-lg-5">
...
<!-- Content of the post -->
</div>
</article>
Here, the differences are:
- Index content does not include the
mb-4
bottom margin class. - Page content is wrapped in a
<main>
element. - Post content is wrapped in an
<article>
element.
Practical Decisions
After reviewing the Clean Blog stylesheet and scripts, I found the following:
-
The
.site-heading
and.page-heading
classes share the same rules. -
The
<article>
and<main>
tags do not have any specific styles or scripts associated with them.
Based on this, my decisions for the theme are straightforward:
- Use
.page-heading
as the class for homepage headings. -
Wrap the entire site content in a
<main class="mb-4">
tag.
What does this mean?
This means I can safely remove all CSS rules related to .site-heading
and unify
the site's content wrapper. Adding some margin to the list of posts on the homepage and
changing the <article>
wrapper for single posts to
<main>
will not affect the structure, responsiveness, or functionality of
the theme.
I'm also going to remove Font Awesome and replace the icons used in the theme with inline SVGs from Feather. Loading an entire icon library just for a few icons isn't a good idea, especially when it comes to performance.
In most cases, there's always a lighter alternative, so don't be lazy and take the
time to look!
Remember:
You don't need a cannon to kill a fly!
Clean Blog Templates
Now that we know what changes we're going to make, it's finally time to break the theme into reusable parts and components. To do this, you'll need to create the following files:
-
In the partials folder:
head.html
menu.html
header.html
content.html
pagination.html
footer.html
-
In the contents folder:
404.html
posts-listing.html
-
In the custom folder:
blog.html
homepage.html
The structure of your clean-blog folder should now look like this:
π clean-blog
βββ π assets
β βββ π css
β β βββ π¨ style.css
β βββ π js
β β βββ π main.js
β βββ π¦ vendors
β βββ π bootstrap.bundle.min.js
βββ π contents
β βββ β 404.html
β βββ π posts-listing.html
βββ π custom
β βββ π° blog.html
β βββ π homepage.html
βββ π partials
β βββ π§© content.html
β βββ π§© footer.html
β βββ π§© head.html
β βββ π§© header.html
β βββ π§© menu.html
βββ π templates
β βββ π§± layout.html
βββ π οΈ theme.json
Look closely: Iβve added a vendors folder inside the
assets directory and included the
Bootstrap scripts
in a file named bootstrap.bundle.min.js
.
You can create the folder and file yourself, then copy and paste the content from the link above into that file.
Now, for the files in the contents, custom, and partials directories, copy and paste the corresponding content provided below into each file based on its name.
head.html
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="description" content="{{metadata.seoDescription || metadata.excerpt || site.siteDescription}}" />
<meta name="author" content="{{metadata.author}}" />
<title>{{homeRoute ? "Home" : metadata.title}} - {{site.siteTitle}}</title>
<link rel="icon" href="/content/uploads{{site.siteIcon}}" />
<!-- Google fonts-->
<link
href="https://fonts.googleapis.com/css?family=Lora:400,700,400italic,700italic"
rel="stylesheet"
type="text/css"
/>
<link
href="https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800"
rel="stylesheet"
type="text/css"
/>
<!-- Core theme CSS (includes Bootstrap)-->
<link href="/content/themes/clean-blog/assets/css/style.css" rel="stylesheet" />
</head>
menu.html
<nav class="navbar navbar-expand-lg navbar-light" id="mainNav">
<div class="container px-4 px-lg-5">
<a class="navbar-brand" href="/">
{{site.siteTitle}}
</a>
<button
class="navbar-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#navbarResponsive"
aria-controls="navbarResponsive"
aria-expanded="false"
aria-label="Toggle navigation"
>
Menu
<!-- Home Feather Icon -->
<svg
xmlns="http://www.w3.org/2000/svg"
width="12"
height="12"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="feather feather-menu"
>
<line x1="3" y1="12" x2="21" y2="12" />
<line x1="3" y1="6" x2="21" y2="6" />
<line x1="3" y1="18" x2="21" y2="18" />
</svg>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ms-auto py-4 py-lg-0">
<!-- Clean Blog menu is a top level menu only. -->
<!-- It doesn't support nested children under a parent. -->
<!-- That's why we retrieve top level items only -->
<!-- Learn more about the Aether Menu System at:
https://aether-cms.pages.dev/documentation/theming/menu-system/ -->
{{#each menuItems}}
<!---->
{{#if depth=0}}
<li class="nav-item">
<a class="nav-link px-lg-3 py-3 py-lg-4" href="{{url}}">
{{title}}
</a>
</li>
{{/if}}
<!---->
{{/each}}
</ul>
</div>
</div>
</nav>
header.html
<header class="masthead" style="background-image: url(/content/uploads{{metadata.featuredImage.url}})">
<div class="container position-relative px-4 px-lg-5">
<div class="row gx-4 gx-lg-5 justify-content-center">
<div class="col-md-10 col-lg-8 col-xl-7">
<div class="{{fileType === `post` ? `post-heading` : `page-heading`}}">
{{#if fileType === "post"}}
<h1>{{metadata.title}}</h1>
{{#if metadata.subtitle}}
<h2 class="subheading">{{metadata.subtitle}}</h2>
{{/if}}
<span class="meta">
Posted by {{metadata.author}} on {{metadata.publishDate | dateFormat("MMMM D, YYYY")}}
</span>
{{#else}}
<h1>{{homeRoute ? site.siteTitle : metadata.title}}</h1>
{{#if homeRoute && site.siteDescription}}
<h2 class="subheading">{{site.siteDescription}}</h2>
{{#elseif metadata.subtitle}}
<h2 class="subheading">{{metadata.subtitle}}</h2>
{{/if}}
<!---->
{{/if}}
</div>
</div>
</div>
</div>
</header>
content.html
<main class="mb-4">
<div class="container px-4 px-lg-5">
<div class="row gx-4 gx-lg-5 justify-content-center">
<div class="col-md-10 col-lg-8 col-xl-7">
<!-- Content by context -->
<!-- Learn more about variables in Aether by visiting:
https://aether-cms.pages.dev/documentation/theming/template-variables-by-context/ -->
{{#if notFoundRoute}}
<!-- If no content has been found, display the 404.html template content -->
{{#include("contents/404.html")}}
<!---->
{{#elseif homeRoute || metadata.slug === "blog"}}
<!-- On the homepage and the blog, display the posts-listing.html template -->
{{#include("contents/posts-listing.html")}}
<!---->
{{#elseif fileType === "post"}}
<!-- For posts, display the post content and pagination -->
{{content}}
<!---->
{{#include("partials/pagination.html")}}
<!---->
{{#else}}
<!-- For normal pages, display the page content -->
{{content}}
<!---->
{{/if}}
</div>
</div>
</div>
</main>
pagination.html
<!-- Creating pagination in Aether is super easy, read more about it at:
https://aether-cms.pages.dev/documentation/theming/working-with-pagination/ -->
{{#if pagination || prevPost || nextPost}}
<!-- Posts pagination -->
<div class="d-flex justify-content-between mb-4">
{{#if pagination.nextPage}}
<!-- Older posts -->
<a href="{{pagination.urls.next}}" class="btn btn-primary text-uppercase" rel="next">β Older Posts</a>
{{/if}}
<!---->
{{#if pagination.prevPage}}
<!-- Newer posts -->
<a href="{{pagination.urls.prev}}" class="btn btn-primary text-uppercase ms-auto" rel="prev">Newer Posts β</a>
{{/if}}
<!---->
{{#if prevPost}}
<!-- Previous Post Link (only if there's a previous post) -->
<a
href="/post/{{prevPost.slug}}"
class="prev-post btn btn-primary btn-sm m-3"
rel="prev"
aria-label="Go to the previous post"
>
Previous: {{prevPost.title}}
</a>
{{/if}}
<!---->
{{#if nextPost}}
<!-- Next Post Link (only if there's a next post) -->
<a
href="/post/{{nextPost.slug}}"
class="next-post btn btn-primary btn-sm m-3 ms-auto"
rel="next"
aria-label="Go to the next post"
>
Next: {{nextPost.title}}
</a>
{{/if}}
</div>
{{/if}}
footer.html
<footer class="border-top">
<div class="container px-4 px-lg-5">
<div class="row gx-4 gx-lg-5 justify-content-center">
<div class="col-md-10 col-lg-8 col-xl-7">
<ul class="list-inline text-center">
<li class="list-inline-item">
<a href="javascript:void(0)" aria-label="Twitter">
<span>
<!-- Twitter Feather Icon -->
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="feather feather-twitter"
aria-hidden="true"
>
<path
d="M23 3a10.9 10.9 0 0 1-3.14 1.53 4.48 4.48 0 0 0-7.86 3v1A10.66 10.66 0 0 1 3 4s-4 9 5 13a11.64 11.64 0 0 1-7 2c9 5 20 0 20-11.5a4.5 4.5 0 0 0-.08-.83A7.72 7.72 0 0 0 23 3z"
></path>
</svg>
</span>
</a>
</li>
<li class="list-inline-item">
<a href="javascript:void(0)" aria-label="Facebook">
<span>
<!-- Facebook Feather Icon -->
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="feather feather-facebook"
aria-hidden="true"
>
<path d="M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3z"></path>
</svg>
</span>
</a>
</li>
<li class="list-inline-item">
<a href="javascript:void(0)" aria-label="GitHub">
<span>
<!-- GitHub Feather Icon -->
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="feather feather-github"
aria-hidden="true"
>
<path
d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"
/>
</svg>
</span>
</a>
</li>
</ul>
<div class="small text-center text-muted fst-italic">
{{site.footerCode}}
</div>
</div>
</div>
</div>
</footer>
404.html
<p>
We couldn't find the page you were looking for. It might have been moved, deleted, or you may have typed the URL
incorrectly. You can return to the homepage to keep exploring.
</p>
<a href="/" class="btn btn-success text-uppercase" rel="next">Okay, Take Me Home!</a>
posts-listing.html
{{#each posts}}
<!-- Post preview-->
<div class="post-preview">
<a href="/post/{{metadata.slug}}">
<h2 class="post-title">{{metadata.title}}</h2>
{{#if metadata.subtitle}}
<h3 class="post-subtitle">{{metadata.subtitle}}</h3>
{{/if}}
</a>
<p class="post-meta">Posted by {{metadata.author}} on {{metadata.publishDate | dateFormat("MMMM D, YYYY")}}</p>
</div>
<!-- Divider-->
<hr class="my-4" />
{{/each}}
<!---->
{{#include("partials/pagination.html")}}
For blog.html
and homepage.html
, you only need to add a single
line to each:
<!-- A simple and effective trick to avoid building a custom page from scratch.
If the design is the same, define its logic as we did in content.html.
Aether's intelligent template inheritance and resolution will handle the rest.
Learn more here: https://aether-cms.pages.dev/documentation/theming/template-inheritance-and-resolution/ -->
{{#include("templates/layout.html")}}
All you have to do after making the necessary replacements is:
- Add some new posts.
-
Add 2 custom pages named
blog
andhomepage
. - Create a menu under the Menu tab in the Site Settings.
- Visit your site.
- Abracadabra! Youβve got a fully working site with a custom Clean Blog theme for Aether.
Wrapping Up
Aether is so flexible that you could recreate Clean Blog in many different ways.
What
Iβve shared here is the simplest version, without making full use of Aetherβs powerful
features.
You can now take this as a foundation, build on it, and create something
entirely new!
Iβve added comments in the templates to help explain each step.
If you have any
questions about this tutorial or Aether in general, feel free to reach out in the
Q&A
section on GitHub.
Soon, Iβll be adding the Clean Blog theme to Aether Marketplace, where youβll be able to
download and use it with just one click.
If you plan to use the custom version created
in this tutorial, you can name the folder custom-clean-blog
and update the
theme.json
title to Custom Clean Blog, just to keep things
consistent.
You may have noticed (or maybe not!), but I never asked you to restart the server at any point in this tutorial. Thatβs one of LiteNodeβs superpowers, the backbone of Aether, which applies changes instantly without needing a reboot.
You can learn more about Aetherβs powerful features in the Aether documentation.
If you find value in Aether or want to help it grow, your support β whether it's feedback, sharing, contributing, or funding β can make a real difference. The long-term goal is to build a sustainable open-source project that stays fast, independent, and truly community-driven. If you'd like to support Aether, giving it a star on GitHub would be greatly appreciated and genuinely helpful.