All pages
On this page
Content and schemas
View as MarkdownFrontmatter, attribute types, validation and queries.
Every collection declares the frontmatter it expects. Files that do not match
fail the build with the file name and the problem, instead of surfacing as
nil in a view.
Declaring attributes
module Content
class Post < Andromeda::Entry
collection :posts, base: "app/content/posts", pattern: "**/*.{md,mdx}"
attribute :title, :string, required: true
attribute :pub_date, :date, required: true
attribute :draft, :boolean, default: false
attribute :tags, :array, of: :string, default: []
attribute :hero_image, :image
attribute :author, :reference, collection: :authors
scope :published, -> { where(draft: false) }
def reading_time = (body.length / 400.0).ceil
end
end| Type | Accepts | Becomes |
|---|---|---|
:string :integer :float :boolean | the matching YAML type | itself |
:date :datetime | 2026-09-01, 'Jul 08 2022', ISO strings | Date / Time |
:array | a list, with of: for the element type | Array |
:enum | one of values: | the value |
:hash | a mapping | Hash |
:image | a path relative to the entry | an image, published through the asset pipeline |
:reference | an id in another collection | the target entry, resolved lazily |
Options: required:, default: (a value or a callable), of:, values:,
collection:.
Frontmatter
YAML (---) and TOML (+++) are both supported. YAML is read with 1.2
semantics, matching Astro: yes and no stay strings, while true and
false are booleans. Dates and timestamps become Date and Time.
Keys are snake_case. Content copied from an Astro project usually has
camelCase keys; bin/rails andromeda:fix rewrites them, and
bin/rails andromeda:check reports them.
Querying
Content::Post.all
Content::Post.published.order(pub_date: :desc).limit(10)
Content::Post.where(draft: false, lang: "en") # every key must match
Content::Post.where { |post| post.tags.include?("rails") }
Content::Post.find("hello-world") # raises Andromeda::EntryNotFoundwhere with a hash compares values for equality, so use the block form to
look inside an array. order is stable: entries that tie keep the order they
were loaded in, as they do in Astro.
Entries expose id, data, body, file_path, digest, html and
headings, plus a reader per declared attribute (post.title).
Entry ids
Ids follow Astro’s glob() loader rules, so URLs from an Astro project keep
working:
| File | Id |
|---|---|
hello-world.md | hello-world |
Guides/Getting Started.md | guides/getting-started |
posts/hello/index.mdx | posts/hello |
a slug: in the frontmatter | that value, verbatim |
Last updated September 24, 2026