With Astro Content, good conventions are preferred over tedious configurations.

That's why this integration follows Astro own philosophy, which promote file based routing.

Similarly, where other content frameworks have chosen imperative, non-standard, centralized content modeling, A.C. works the opposite way. The ubiquitous, declarative JSON schemas are first-class citizen, and are placed in the corresponding entity folder, which make it ultimately portable.


Astro Content uses JSON Schema under the hood for all your content lifetime:
From designing, to importing then finally, rendering in your templates.

See the official JSON Schema tutorial .

For example, this is the schema used for all /docs pages you are currently viewing:

From: 📄  /docs/content/docs/doc-section.schema.yaml
        type: string
        type: number

      - title
      - order

    additionalProperties: false

  - main

additionalProperties: false

It is co-located with the actual content, so it is portable:


├── doc-section.schema.yaml

├── development
│   └── main.md
├── import
│   └── main.md
├── install
│   └── main.md
├── modeling
│   └── main.mdx

└── ...

See the doc. sections content for inspiration.


Content hierarchy

Conventions are modeled upon this relatively flat hierarchy:


…which practically gives:


Why this 3-levels nesting?
Here is the logic behind this:

Please note that a property (file) itself, like a <person>/contact.{md,mdx,yaml} can host as many levels as you need.
It's JSON, in the end, even if it is expressed in pure YAML or YAML in Markdown front matter.

Note: Astro Content might support content base switching in the future, that means one more level, if you really need it.
In the meanwhile, you can merge entities, when glob-importing, with symbolic links (see Tips and Tricks section), or simply using different Astro projects, if it's OK for you.

It should be possible to make Astro Content support indefinite levels of nesting,
reflecting your own intricate schema design. But for now, it will make development too convoluted, while not being desirable in most cases, so we stick to the widely spread conventions described above.

If you feel like a property (file) is going into a black hole, with multiples sub-properties, extract it to a new entity, then make cross-references, later resolved in your application itself (see MongoDB development patterns).

Directory structure

Example directory structure for your ./content base:

├── default.schema.yaml           # <- Mother of all newly created entities,
#    it's customizable.

├── [entities]                    # —————————————— Theoretical model ———————————
│   │
│   ├── [entity].schema.yaml      # <- Actual schema defining single entries.
│   ├── [entry]
│   │   ├── [property-a].yaml
│   │   ├── [property-b].yaml     # <- Property (file) can be optional.
│   │   └── [property-c].md
│   │
│   │
│   │                             # —————————————— Real world examples —————————
├── people
│   ├── person.schema.yaml        # <- Notice singular entity name for schema.
│   ├── pierre-corneille
│   │   ├── gallery.yaml
│   │   └── biography.md
│   ├── jean-racine
│   │   ├── gallery.yaml
│   │   ├── references.yaml
│   │   └── biography.md
│   │
├── pages
│   ├── page.schema.yaml          # <- An entry can share ALL, SOME,
│   ├── home                      #    or NONE of schema defined properties.
│   │   ├── header.md
│   │   ├── main.md
│   │   └── footnotes.md
│   ├── contact
│   │   ├── main.md
│   │   ├── resume.md
│   │   └── links.yaml
│   ├── not-found
│   │   ├── message.md
│   │   └── cool-meme.md
├── ...
│   └── ...

└── index.ts                      # <- Import helper. You can ignore it.

Entries can share the same features, can have some of their own, or even be totally independent.
That's it: an entry can be part of a collection like "My vacation" in "Blog posts", or a singleton like "My resume" in "Web pages".

An entry is a flexible concept. As a part of an entity, you could make it relaxed, or very strict.
Astro Content doesn't care on how you design your content base, it's up to you.

Entries singularity spectrum:

Shares ALL features
Shares SOME features
Shares NO features


Naming can be done inside JSON Schemas themselves with title, or if not set, will be inferred from your file paths.

my-blog-post/foot-notes.md automatically becomes "My blog post > Foot notes" for display and myBlogPost.footNotes for JavaScript object notation.

Tips and tricks