Introduction to Kirby CMS

Share this article

Kirby is a lightweight CMS that probably fits somewhere between feature-rich platforms such as Drupal, and static site generators such as Jekyll.

What makes Kirby quite different to most CMS’s – and closer to Jekyll in the process – is that it has no database. Instead, everything is stored as files; some for configuration, some for content – all in addition to the usual template files, partials and plugins.

In this article I’m going to take a look at Kirby, demonstrate how to use it, and assess some of its strengths and weaknesses.

Licensing, Downloading and Installing

Kirby is provided on the basis of a per-site license of (at time of writing) $39 USD. However, you can try it out on your local machine for free – it’s only when you get into production that the license fee becomes payable.

The package is available from the Kirby Downloads page as a .zip file, or from Github.

To install, unzip / copy the archive to your web root and point your virtual host at Kirby’s root directory. And that’s pretty much it – right away, you should see some dummy content and Kirby’s default theme.

The Default Kirby theme

Kirby’s Site Structure

Let’s suppose we plan to work with the basic site structure provided by default, but add a new page at the top-level called “Our Work”. We want it to appear before “Contact” in the menu.

Start by renaming the directory which holds the contact page from content/03-contact to content/05-contact.

By default, the menu system uses the directory name to determine the order pages should appear in the navigation. We’ll create a new page for the fourth position later.

Now, create a new folder called content/03-our-work, and in that a file called our-work.txt

Content files should always have a .txt extension by default, despite their content being a mixture of YAML and Markdown. To modify this behaviour, change the following line in site/config/config.php:

c::set('content.file.extension', 'txt');    

The file should have the following structure:

Title: Our Work
Text: Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor.

Now, if you browse to the site you should see a new menu item in between Projects and Contact, with the content we just defined in 04-our-work/our-work.txt.

Obviously, you can edit existing pages in the same way. You’ll find the contents of the homepage in content/home/home.txt.

Let’s take a look at how the menu is built to get an insight into what’s going on. The menu is implemented as a snippet, which is basically a view partial:

// site/snippets/menu.php

<nav class="menu">
    <?php foreach($pages->visible() AS $p): ?>
    <li><a<?php echo ($p->isOpen()) ? ' class="active"' : '' ?> href="<?php echo $p->url() ?>"><?php echo html($p->title()) ?></a></li>
    <?php endforeach ?>

Notice that it calls a method called visible(). Content prefixed with a number – 01, 02 etc – is visible; that is, it’s designed to appear in the navigation. Content without – such as home and error – is hidden. Try creating a folder called content/test, with a corresponding content file called test.txt – you’ll find that it doesn’t appear on the menu. If you want to hide additional pages, change the following line in site/config/config.php:

c::set('content.file.ignore', array());

$pages->visible() returns pages ordered by directory name, hence the numeric prefixes. You can override that behaviour; suppose you wanted a list of pages alphabetically ordered by title:

$a_to_z = $pages->visible()->sortBy('title', 'asc');

To list pages beneath the currently open menu item (i.e., a sub-menu) you can do this:

if($root = $pages->findOpen()) {
$items = $root->children()->visible();    

There’s lots more information on managing menus on the Kirby website.


In a new installation, pages are rendered using site/templates/default.php.

Let’s take a look at the contents:

<?php snippet('header') ?>
<?php snippet('menu') ?>
<?php snippet('submenu') ?>

<section class="content">

    <h1><?php echo html($page->title()) ?></h1>
    <h2><?php echo html($page->subtitle()) ?></h2>
    <?php echo kirbytext($page->text()) ?>


<?php snippet('footer') ?>

snippet() includes a file from site/snippets – we’ll look at those shortly.

You’ll notice that the page content is available as a variable called $page, which reads the properties defined in the corresponding text file. The html() function is used to escape values, and kirbytext() applies some additional interpretation, as we’ll see shortly.

To create a new template for a specific page, simply create a new file in site/templates whose name matches the filename of the content for the page in question. So, for example, if you want a separate page template for the homepage, you’d create a file named site/templates/home.php. For the “Our Work” page we created earlier, you’d call it our-work.php.

By default, with Kirby comes an assets folder, containing images and styles sub-folders, but you’re free to structure your theme’s assets as you wish.

Site Properties, and Snippets

If you open up the file content/site.txt, you’ll see a bunch of properties of the site itself such as the title, author and copyright notice. You’re free to add additional properties. For example, if you add the following:


Twitter: myusername

You can now print this out in your templates or snippets, using a magic method of the $site variable. So to put it in the footer, open up site/snippets/footer.php and add the following:

<a href="<?php print $site->twitter() ?>">Twitter</a>

Creating a Simple Blog

We’ve seen how to create content, create a page-specific template and generate a list of pages. Armed with this knowledge, creating a simple blog is pretty straightforward.

Create a folder called content/04-blog and in it, a file called blog.txt:

Title: Blog

Within that folder, create a bunch of blog posts (using the same format as the existing pages), e.g.


Now, create a template for the Blog:

// site/templates/blog.php

<?php snippet('header') ?>
<?php snippet('menu') ?>

<section class="content">

    <h1><?php echo html($page->title()) ?></h1>

    <?php foreach ($pages->findOpen()->children()->visible()->flip() as $post): ?>
    <h2><a href="<?php print $post->url() ?>"><?php echo html($post->title()) ?></a></h2>
    <p><?php print excerpt($post->text()) ?></p>
    <p><a href="<?php print $post->url() ?>">Read more &raquo;</a></p>
    <?php endforeach ?>


<?php snippet('footer') ?>

Notice how we’re calling flip() to reverse the order of the pages, all of whom are children of the current page – i.e., pages within the content/04-blog folder.

This template also introduces the url() function, which returns a URL to the page in question, and excerpt(), which returns a summary of the text content. To change the number of characters returned, simply provide it as a second parameter:

print excerpt($post->text(), 250); // prints the first 250 characters


The actual content in Kirby is written in “Kirbytext”. It’s stored as the text property in a YAML file, and is essentially an extension of Markdown but with some additional macros.

This is best illustrated with an example:

File: page.txt:

Title: About
Somefield: Something
Body: This is some sample content. It's based on Markdown, so we can use **bold** or *emphasis*, and [write links](

Kirbytext also has macros, that look a little like this:

(youtube: width: 300 height: 200)

The Kirby-specific macro / tag here is for embedding a Youtube video, but you can extend Kirbytext to write your own. To do so, start by creating a file called kirbytext.extended.php in site/plugins:

class kirbytextExtended extends kirbytext {

function __construct($text, $markdown=true) {

    parent::__construct($text, $markdown);



Now, in the constructor you can define new tags, as well as new attributes. Suppose we wanted to add Gravatar support:

    // define custom tags

    // define custom attributes

Once you’ve defined a new tag through addTags(), you simply implement a method with the same name, which will be called in order to render the tag:

*  Render the gravatar tag, e.g. (gravatar:
function gravatar($params) {

    $email = $params['gravatar'];

    $size = (isset($params['size'])) ? $params['size'] : 50;

    $url = sprintf('', md5($email), $size);

    return sprintf('<img src="%s" width="%d" height="%d" />', $url, $size, $size);


You’d use this as follows:

(gravatar: size: 64)

Note that the email attribute here is named gravatar; i.e., the same as the tag.


There are a number of plugins available on Github including support for Twitter, Instagram and Github, as well as things like contact forms, estimating reading time and displaying related pages.

You can create your own plugins with little to no knowledge of Kirby’s inner workings – simply drop a class into site/plugins and use it from your templates as required.

Kirby Panel

Kirby doesn’t actually provide any sort of administrative interface out-the-box – you simply edit the files directly. However, there is a simple interface available as a separate package, called Kirby Panel.

The Kirby Panel

To install Kirby Panel, clone it from Github.

Then, copy the folder to the site folder of your Kirby site, naming it panel, e.g.:

cp -R kirbycms-panel/ /var/www/yoursite/site/panel

Now copy the panel\defaults folder and place it in the site root:

cp -R /var/www/yoursite/panel/defaults /var/www/yoursite/panel

To specify some login credentials, rename the file site/panel/accounts/admin.php to [username].php, e.g.:

// site/panel/accounts/john.php

<?php if(!defined('KIRBY')) exit ?>
username: john
password: 5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8
encrypt: sha1
language: en

You can enter a plaintext password (a very, very bad idea), an MD5 hash (a very bad idea) or an SHA1 hash (marginally better) – you just need to explicitly specify which you’re using, or leave it out for plaintext.

Now, if you open http://yoursite.local/panel in your web browser, you’ll have access to a simple administrative interface. This allows you to modify site properties, as well as add / edit / delete content.

Pros and Cons

Let’s look briefly at some of Kirby’s pros and cons.


  • Extremely simple to install
  • Fast
  • Results in clean markup
  • Very shallow learning curve
  • Very little bloat


  • Some of the code tries to reinvent the wheel, for example the device detection
  • Everything sits in the public root, which isn’t particularly logical
  • Dynamic elements such as search are limited at best


I’ve given you a brief introduction of Kirby, but there’s plenty more to explore – check out the documentation and tutorials, find support in the forums, or delve into the source-code. In particular, take a look at kirby/lib/kirby.php, along with the other files in kirby/lib.

What do you think of Kirby, and what might you use it for? Have you already used it in production? Let me know in the comments.

Frequently Asked Questions (FAQs) about Kirby CMS

What Makes Kirby CMS Different from Other Content Management Systems?

Kirby CMS stands out from other content management systems due to its simplicity and flexibility. Unlike other CMSs that use databases, Kirby CMS is a file-based system. This means that all your content is stored in text files, making it easier to manage, backup, and version control. Additionally, Kirby CMS is highly customizable, allowing you to design your website exactly how you want it without any restrictions.

How Do I Install Kirby CMS?

Installing Kirby CMS is straightforward. You can download the latest version from the official Kirby website. Once downloaded, you need to unzip the file and upload it to your server. After uploading, navigate to your site’s URL, and Kirby will guide you through the setup process.

Can I Use Kirby CMS Without Coding Knowledge?

Yes, you can use Kirby CMS without any coding knowledge. Kirby CMS offers a user-friendly panel that allows you to manage your content easily. However, if you want to customize your site, some basic knowledge of HTML, CSS, and PHP would be beneficial.

How Secure is Kirby CMS?

Kirby CMS is designed with security in mind. It uses file-based storage, which reduces the risk of SQL injection attacks. Additionally, Kirby CMS has built-in protection against cross-site scripting (XSS) and cross-site request forgery (CSRF) attacks.

How Do I Update Kirby CMS?

Updating Kirby CMS is as simple as replacing the old Kirby folder with the new one. However, before updating, it’s recommended to backup your site and test the update in a local environment.

Can I Use Kirby CMS for E-commerce?

Yes, Kirby CMS can be used for e-commerce. There are several plugins available that add e-commerce functionality to Kirby CMS, allowing you to manage products, handle payments, and track orders.

How Do I Create a New Page in Kirby CMS?

Creating a new page in Kirby CMS is easy. You simply create a new folder in the content directory, and Kirby CMS automatically recognizes it as a new page. You can then add content to the page by creating a text file in the folder.

Can I Use Kirby CMS for Blogging?

Yes, Kirby CMS is an excellent choice for blogging. It offers a simple and intuitive interface for managing blog posts. You can also add categories, tags, and author profiles to your blog posts.

How Do I Add Images to My Kirby CMS Site?

Adding images to your Kirby CMS site is straightforward. You can upload images directly through the panel, or you can add them manually by placing them in the content folder. Once uploaded, you can display the images on your site using Kirby’s built-in image handling functions.

Can I Use Kirby CMS with a Custom Domain?

Yes, you can use Kirby CMS with a custom domain. Once you’ve set up Kirby CMS on your server, you can point your custom domain to the server’s IP address. This allows you to access your Kirby CMS site using your custom domain.

Lukas WhiteLukas White
View Author

Lukas is a freelance web and mobile developer based in Manchester in the North of England. He's been developing in PHP since moving away from those early days in web development of using all manner of tools such as Java Server Pages, classic ASP and XML data islands, along with JavaScript - back when it really was JavaScript and Netscape ruled the roost. When he's not developing websites and mobile applications and complaining that this was all fields, Lukas likes to cook all manner of World foods.

Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week
Loading form