Skip to content

Data Introudction

How the JSON-driven data system works in Astro Docus — write once, reuse everywhere.

Section titled “”
Configuration & Setup

Configuration & Setup

Navbar, blog meta, and footer for every page.

Homepage

Homepage

Landing page content — hero, features, tech, help.

Pricing Page

Pricing Page

Plan content and price tiers in two JSON files.

Contact Page

Contact Page

Contact info and Formspree integration.

Static Page

Static Page

Create custom pages with Markdown and layouts.

Docs Page Card

Docs Page Card

Card grids for documentation index pages.

Astro Docus is built on a simple principle: content lives in JSON, not in code. This is often called a non-hardcoded or JSON-driven approach.

Instead of writing text directly inside .astro components, you store it in .json files under src/data/. Components then import those JSON files and loop through them to render content.

This has three big advantages:

  1. Easy to update — change text without touching any code.
  2. Reusable — the same data can feed multiple pages or widgets.
  3. Safe — non-developers can edit JSON without breaking components.

All JSON content lives in one place:

src/data/
├── home.json
├── configuration/
│ ├── blog/
│ │ └── blogpage.json
│ └── home/
│ └── homepage.json
├── index_page/
│ ├── cms.json
│ ├── folder.json
│ ├── getstart.json
│ ├── hosting.json
│ └── services.json
├── plan/
│ └── data.json
└── pricing/
└── pricing.json

Each folder or file serves a specific purpose. We will walk through them one at a time in separate pages under docs/data/.


The flow is always the same:

JSON file → .astro widget → .mdx page → rendered website

Let’s break it down with a real example.

src/data/index_page/getstart.json contains a list of resources:

{
"resources": [
{
"title": "Installation",
"image": "/src/assets/install.svg",
"text": "Set up Astro Docus on your machine.",
"link": "/getstart/installation/"
},
{
"title": "Configuration",
"image": "/src/assets/data.svg",
"text": "Configure the main brain of the project.",
"link": "/getstart/configuration/"
}
]
}

src/widget/index_page/getstart.astro imports the JSON and loops through it:

---
import Data from '../../data/index_page/getstart.json';
import { Picture } from 'astro:assets';
---
<div class="grid-container">
{ Data.resources.map(({ title, image, text, link }) => (
<div class="grid-item">
<a href={link}>
<Picture
src={image}
alt={title}
formats={['avif', 'webp']}
width="80"
height="80"
class="img-fluid"
decoding="async"
/>
</a>
<h3><a href={link}>{title}</a></h3>
<p>{text}</p>
</div>
))}
</div>

What is happening here:

  • import Data from '...' — loads the JSON file into a variable.
  • Data.resources.map(...) — loops through every item in the resources array.
  • { title, image, text, link } — destructures each item so we can use its fields directly.
  • <Picture /> — Astro’s built-in image component, optimized for performance.

Every field in the JSON maps directly to something rendered on the page.

src/content/docs/getstart/index.mdx imports the widget and displays it:

---
title: Get Start
description: Get Started with Astro Docus template
tableOfContents: false
next: false
---
import Start from '../../../widget/index_page/getstart.astro';
import '../../../styles/index_page.css';
## {frontmatter.description}
<Start />

What is happening here:

  • import Start from '...' — loads the widget component.
  • import '.../index_page.css' — loads the styles specific to this page.
  • ## {frontmatter.description} — renders the description from the frontmatter as an H2.
  • <Start /> — renders the widget, which renders the looped JSON data.

Result: a grid of cards, all generated from one JSON file.


Every card would have to be typed manually:

<div class="grid-item">
<a href="/getstart/installation/">
<img src="/src/assets/install.svg" alt="Installation" />
</a>
<h3><a href="/getstart/installation/">Installation</a></h3>
<p>Set up Astro Docus on your machine.</p>
</div>
<div class="grid-item">
<a href="/getstart/configuration/">
<img src="/src/assets/data.svg" alt="Configuration" />
</a>
<h3><a href="/getstart/configuration/">Configuration</a></h3>
<p>Configure the main brain of the project.</p>
</div>
<!-- ...and so on for every card -->

Adding a new card means writing more HTML. Changing a link means hunting it down in multiple places.

The same cards come from one array. To add a new card, you add one object to the JSON file:

{
"title": "New Page",
"image": "/src/assets/new.svg",
"text": "Description here.",
"link": "/getstart/new-page/"
}

That’s it. The widget already knows how to render it.


The folder src/data/index_page/ deserves special attention.

Each JSON file in this folder maps to a documentation index page:

JSON filePowers the page
index_page/getstart.json/getstart/
index_page/cms.json/cms/
index_page/hosting.json/deploy-hosting/
index_page/services.json/services/
index_page/folder.jsonUsed for folder documentation

The pattern is:

  1. You write a page like src/content/docs/getstart/index.mdx.
  2. That page imports a widget like src/widget/index_page/getstart.astro.
  3. That widget reads src/data/index_page/getstart.json and loops through the items.

So when you want to add a new card to the Get Started landing page, you only edit getstart.json — nothing else.

This is what we mean by automatic looping from data. The JSON drives the page.


The src/data/ folder is divided into four conceptual groups. Each will get its own page in this documentation.

FolderPurpose
configuration/Site-wide settings for blog and homepage
index_page/Card grids for documentation landing pages
plan/Plan comparison data
pricing/Pricing table data

Each of these will be explained in detail under docs/data/*.md as we go. This page is only the introduction — the why and the how.


When working with the data system, keep these rules in mind:

  1. Never hardcode content that already exists in JSON. If a card, price, or menu item is in JSON, edit the JSON.
  2. Always keep the JSON shape consistent. If a widget expects title, image, text, link, every object in the array must have those keys.
  3. Import paths are relative. From src/widget/index_page/getstart.astro, the JSON path is ../../data/index_page/getstart.json.
  4. JSON does not allow comments. If you want to leave notes, add a "_note" field or document it in Markdown.
  5. JSON does not allow trailing commas. One typo can break the whole build.

JSON file → widget (.astro) → page (.mdx) → rendered site
Example:
src/data/index_page/getstart.json
→ src/widget/index_page/getstart.astro
→ src/content/docs/getstart/index.mdx
→ https://yoursite.com/getstart/

Once you understand this chain, you understand the entire data system of Astro Docus. Everything else is just variations of this pattern.

👉 Continue to the next page to learn about each JSON file in detail: docs/data/*.md