Grav is an open source flat-file CMS platform, built by the RocketTheme Team. While there are plenty of great CMS platforms available, they are all mostly database-driven, which can be overkill for smaller websites. Instead of a database, Grav uses folders and a basic file structure, it is focused on speed, simplicity, and flexibility.

After reading all of the documentation and spending some time trying Grav out, I’m definitely sold and will be using the platform. I hope you will too.

What We’ll Be Building

For the first part of this tutorial we’ll be building a one-page website, and in the second part, we’ll build a simple blog. I’ll assume you have a good understanding of HTML and CSS (or CSS preprocessors). We will not be getting into the styling of the themes but rather focus on Grav, and its functionality.

You can check out both of these themes on GitHub:

Installing Grav

Below are the very few requirements Grav needs in order for it to run:

  • A web server (Apache, Nginx, LiteSpeed, Lightly, IIS, etc.)
  • PHP 5.5.9 or higher

Download Grav Core with the Admin Panel Plugin and unzip the package in the webroot of your web server and you’re ready to roll.

Page Types

Grav comes with 3 types of pages out of the box:

Standard Page

These are typically single pages, such as blog posts, contact pages, error pages, etc. Grav assumes that any page is a standard page unless otherwise specified.

Listing Page

These are basically a standard page that has a reference to a collection of pages, for an example, a blog listing page. Configuration settings for these pages include: order, number of items and whether or not pagination is enabled.

Modular Page

Modular pages build a single page from it’s child pages, allowing us to build one-page layouts from smaller modular pages.

File Structure

Generally speaking, the only folder you’ll use is the /user folder.

The Content

The /user/pages folder is where all of the content pages live. Each page is placed in its own folder, and folder names should reflect the page’s name, and also be a valid slug.

You can order pages by naming the page folders with a preceding number: 01.home, Page folders then contain a markdown file and media for the page. The name of the markdown file will reference the name of the theme’s template to be used to render the content, for example: would look for a template named home.html.twig.

The Theme

Themes can be found within the /user/themes folder. For a theme to function you’ll need:

  • blueprints.yaml – a file which contains information about the theme.
  • themename.php – a file which contains any logic your theme needs.
  • themename.yaml – a configuration file used by the plugin to set options the theme might use.
  • templates/ – a folder containing the Twig templates to render the pages.

You should also include and these are required if you plan to release a theme:

  • – a file that follows the Grav Changelog Format to show changes.
  • LICENSE – a file containing the license to the theme.
  • – a file with documentation for the theme.
  • screenshot.jpg – a 1009px x 1009px screenshot of the theme.
  • thumbnail.jpg – a 300px x 300px screenshot of the theme.

This is also where the css, sass, fonts, images, and js folders for the theme reside.

The Templates

Templates can be found in the /user/themes/themename/templates folder. These templates are Twig templates and will be used to render your pages.

The Blueprints

Blueprints are located in the /user/themes/themename/blueprints folder. The files within this folder are YAML files used to extend and modify the admin plugin with custom forms to make updating the website simpler.

Part 1: One Pager modular theme

Now that we have a basic understanding of how Grav works, let’s get started on our first Grav theme: a one page theme showcasing Grav’s awesomeness. Below is what our content and themes folder are going to look like:

Content File Structure

├── 01.home
│   ├── _download
│   │   └──
│   ├── _features
│   │   └──
│   ├── _highlights
│   │   └──
│   ├── _intro
│   │   └──
│   ├── _overview
│   │   ├── grav-logo.png
│   │   └──
│   └──

Theme File Structure

├── blueprints
│   └── modular
│       ├── highlights.yaml
│       └── showcase.yaml
├── css
│   └── main.css
├── fonts
├── imgs
├── js
├── sass
├── templates
│   ├── home.html.twig
│   ├── modular
│   │   ├── download.html.twig
│   │   ├── features.html.twig
│   │   ├── highlights.html.twig
│   │   ├── intro.html.twig
│   │   └── overview.html.twig
│   └── partials
│       └── base.html.twig
├── blueprints.yaml
├── onepager.yaml
├── screenshot.jpg
└── thumbnail.jpg

Config Files


The site’s configuration file. We should never edit the default configuration files found in system/config. Instead, we overwrite the settings we’d like to change via creating our own configuration files within user/config. Below is a simple version of a site configuration file.

For more complex configurations, have a look at the documentation.

title: 'One Pager'
    name: 'Angie Vella'
    email: ''
    generator: 'Grav'
    description: 'Simple One Page Theme for Grav'
    keywords: 'HTML, CSS, Grav, Theme, One Page'
    author: 'Angie Vella'
    robots: 'noindex, nofollow'

Theme Files

As mentioned before, there are a couple of files Grav requires for a theme to function.


This file defines theme information and configuration options to be shown in the Admin panel. Blueprints are defined with YAML and below is our blueprints file for our One Pager Theme.

name: One Pager
version: 1.0.0
description: "A simple one page theme for Grav"
    name: Angie Vella
license: MIT


This file contains theme configuration, like the blueprints file this is also defined in YAML. For this example we’ll keep it super simple.

enabled: true
default_lang: en

Theme Templates

Now that we have the files the theme requires to function, it’s time to get started on the Twig templates. These templates will be used to render our content.


The base template is just that: the template that will be the base of our theme. We’ll be extending this template within our other templates. Let’s break it down:

<html lang=”{{ theme_config.default_lang }}”> – Gets the configuration set in onepager.yaml.

{% block head %}{% endblock head %} – This defines an area in the base template, typically containing the stuff we put in the<head>element. Note that the head in {% endblock %} is not required, but can be used for readability.

<title>{{ site.title }}</title> – Pulls the configuration set in config/site.yaml.

<link rel=”canonical” href=”{{ page.url(true, true) }}”> – Sets a canonical URL for the page.

<link rel=”icon” type=”image/png” href=”{{ url(‘theme://img/favicon.png’) }}”> – Points to the site’s favicons, located in the theme/imgs directory.

{% block stylesheets %} – Within this block we register our stylesheets for the theme.

{{ assets.css() }} – This outputs the stylesheets we just registered.

{% block javascripts %} – Just like the stylesheets block this registers our JavaScript files for the theme. Note that the jQuery library comes bundled with Grav.

{{ assets.js() }} – Renders the scripts we just registered.

<a href=”{{ base_url}}”>OnePager</a> – Links to the home page.