Skip to content

Grav Pages & Content — Creating Your First Pages

DodaTech Updated 2026-06-27 5 min read

In this tutorial, you'll create real pages in Grav and understand how Grav's folder-based page system works.

What You'll Learn

  • How Grav maps folder names to URLs
  • How to create a home page and a sub-page
  • YAML frontmatter fields and what they control
  • Page types (default, blog, item, etc.) and template mapping

Why It Matters

In WordPress, creating a page means logging into the admin panel, clicking "Add New," filling in fields, and hitting "Publish." In Grav, creating a page means creating a folder and writing a Markdown file. This direct mapping between filesystem and website is what makes Grav Git-friendly, editor-agnostic, and fast.

Real-World Use

At DodaTech, content teams use Grav for documentation sites where each page corresponds to a product or feature. A developer creates the folder and Markdown file, a technical writer edits the content in their preferred editor, and everything is version-controlled in Git — no admin panel required.

How Grav Maps Folders to URLs

Each page in Grav is a folder inside user/pages/. The folder name determines the URL:

user/pages/
├── 01.home/          →  /
├── 02.about/         →  /about
├── 03.blog/          →  /blog
│   └── 01.my-post/   →  /blog/my-post
└── 04.contact/       →  /contact

The number prefix (01., 02.) is stripped from the URL but controls ordering in menus and listings.

Rule of thumb: The folder name (without the number prefix) becomes the URL slug. The Markdown file inside is the content.

Creating a Home Page

Step 1: Create the Folder

mkdir -p user/pages/01.home

Step 2: Create default.md

Every page needs a Markdown file. The filename determines the template type:

  • default.md — Uses the default.html.twig template
  • blog.md — Uses the blog.html.twig template
  • item.md — Uses the item.html.twig template (for child items)

Create user/pages/01.home/default.md:

---
title: Home
menu: Home
published: true
body_classes: home-page
---

# Welcome to My Grav Site

This is the home page of my **Grav-powered** documentation site.

## What You'll Find Here

- Tutorials and guides
- API documentation
- Project examples

Grav makes it easy to create and manage content without a database.

Visit http://localhost:8000 — you'll see your new home page.

Frontmatter Fields Explained

Field Purpose Example
title Page title (appears in <title> and templates) title: Home
menu Custom menu label (defaults to title) menu: Home
published Whether the page is visible published: true
body_classes CSS classes for the body tag body_classes: home-page
route Custom URL (overrides the folder-based URL) route: /welcome
visible Whether the page appears in menus visible: true
template Force a specific template template: custom

Creating an About Page

Create user/pages/02.about/default.md:

---
title: About
menu: About
published: true
---

# About This Site

This site is built with **Grav CMS**, a flat-file content management system.

### What is Flat-File?

Flat-file means no database. Every page is a Markdown file stored on disk. This makes the site:

- **Fast** — No database queries
- **Secure** — No SQL injection attacks
- **Portable** — Copy files to move the site
- **Git-friendly** — Version control out of the box

### Built by DodaTech

This documentation site is maintained by the team behind Doda Browser, DodaZIP, and Durga Antivirus Pro.

Visit http://localhost:8000/about — your About page is live.

Page Types and Templates

Grav uses the Markdown filename to determine which Twig template renders the page:

Filename Template Use Case
default.md default.html.twig Standard pages
blog.md blog.html.twig Blog listing (shows child pages)
item.md item.html.twig Individual blog post
modular.md Modular templates Modular page with sub-sections
form.md form.html.twig Contact/feedback forms

Example: Blog Page

A blog listing page uses blog.md:

---
title: Blog
menu: Blog
published: true
---

# Blog

Latest posts from the team.

And each blog post uses item.md inside a numbered subfolder:

user/pages/03.blog/
├── blog.md                  # /blog — listing page
├── 01.first-post/
│   └── item.md             # /blog/first-post
└── 02.second-post/
    └── item.md             # /blog/second-post

Content in Multiple Languages

Grav supports multi-language content out of the box. Add a language suffix to frontmatter or use separate files:

---
title: Home
title@es: Inicio
title@fr: Accueil
---

Or use separate files per language:

01.home/
├── default.md          # English (default)
├── default.es.md       # Spanish
└── default.fr.md       # French

Enable languages in system.yaml:

languages:
    supported:
        - en
        - es
        - fr
    default_lang: en

Common Mistakes

Mistake Why Fix
Page shows 404 Folder not in user/pages/ or incorrect path Check the folder structure matches the URL
Page not visible published: false or missing published field Set published: true in frontmatter
Wrong template used Markdown filename doesn't match a template Use default.md unless you have a custom template
Menu item not appearing visible: false or no menu field Add menu: My Page to frontmatter
URL has number prefix in it Folder name has spaces in the number prefix Use dots: 01.page-name, not 01 page name

Editing Without the Admin Panel

One of Grav's superpowers: you can edit pages with any text editor.

# Edit the home page
nano user/pages/01.home/default.md

# The change is live immediately

This works because Grav reads Markdown files from disk on every request (cached in production). For development, changes appear after a page refresh.

Learning Path

flowchart LR
  A["What is Grav?"] --> B["Installation"]
  B --> C["Pages & Content
← You are here"]:::current C --> D["Navigation"] D --> E["Twig Templating"] E --> F["Themes"] F --> G["Taxonomy & Blog"] G --> H["Plugins & Admin"] H --> I["Configuration & Caching"] I --> J["Deployment & Maintenance"] classDef current fill:#38bdf8,color:#0f172a,stroke-width:2px

Practice Questions

  1. What determines a page's URL in Grav? Answer: The folder name in user/pages/. The number prefix is stripped; the rest becomes the URL slug.

  2. What are the three common Markdown filenames and their template types? Answer: default.md (standard page), blog.md (blog listing), item.md (blog post).

  3. What happens if a folder has no Markdown file? Answer: Grav returns a 404 error. Every page folder must contain at least one .md file.

  4. How do you create a child page? Answer: Create a numbered subfolder inside the parent page folder, with its own .md file.

  5. Challenge: Create a "Projects" page (/projects) with three sub-pages (/projects/project-a, /projects/project-b, /projects/project-c), each with unique content. Verify all four pages render correctly.

What's Next

Your site has content. Now let's organize it:

Continue to Lesson 4: Navigation & Menus — Control how pages appear in menus and create custom navigation.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro