Grav Pages & Content — Creating Your First Pages
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 thedefault.html.twigtemplateblog.md— Uses theblog.html.twigtemplateitem.md— Uses theitem.html.twigtemplate (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
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.What are the three common Markdown filenames and their template types? Answer:
default.md(standard page),blog.md(blog listing),item.md(blog post).What happens if a folder has no Markdown file? Answer: Grav returns a 404 error. Every page folder must contain at least one
.mdfile.How do you create a child page? Answer: Create a numbered subfolder inside the parent page folder, with its own
.mdfile.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