Detection
What Gitupcms reads from your Astro project, so you never write a CMS config file.
Gitupcms reads the project the same way Astro does. If Astro loads it, Gitupcms can edit it.
| Source | What Gitupcms takes from it |
|---|---|
src/content.config.ts (or legacy src/content/config.ts) |
Collections with a glob() loader: base, pattern (string or array, ! excludes). Formats: md, mdx, mdoc, json, yaml, toml. The Zod schema becomes field types, required/optional, defaults, z.enum options, reference() and image() |
file() loader collections |
Site data: navigation, footer, settings. One JSON, YAML or TOML file |
src/content/<folder>/ |
Only with legacy.collectionsBackwardsCompat in astro.config, as Astro does |
| Frontmatter of existing entries | Fields the schema does not list (string, text, number, boolean, date, image, list, object) |
| Most common file extension | The format of new entries (.md, .mdx, .json, .yaml) |
| First existing media folder | public/images, public/img, public/uploads, public/assets, src/assets/images, src/assets, public |
.astro/collections/*.json |
When the repo tracks Astro’s own JSON Schemas (astro sync), the exact fields come from there |
Schemas
Schemas in variables, .extend(), .pick(), .omit(), .partial() and ...x.shape spreads are understood. Keys the schema does not list are hidden, because Zod drops them, unless the schema is loose (z.looseObject, .passthrough()). With no schema, fields come from the entries themselves.
import { defineCollection, reference, z } from "astro:content";
import { glob } from "astro/loaders";
const blog = defineCollection({
loader: glob({ base: "./src/content/blog", pattern: "**/*.md" }),
schema: ({ image }) =>
z.object({
title: z.string(),
date: z.coerce.date(),
cover: image().optional(),
author: reference("authors"),
tags: z.array(z.string()).default([]),
draft: z.boolean().default(false),
}),
});
export const collections = { blog };
This gives a form with a text field, a date picker, an image picker, an author select, a tag list and a Draft switch.
Image paths
Image fields store /images/x.png for media in public/, and a path relative to the entry (../../assets/x.png) for media in src/, which is what Astro’s image() needs.