---
title: Detection
description: 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.

```ts src/content.config.ts
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.

:::note
No loader means Astro loads nothing, so Gitupcms shows nothing either. Add a `glob()` loader and the collection appears.
:::
