How Zeku reads your site
Zeku has no project file of its own. Everything it knows about your site, it reads from your site, every time you open it.
Collections
Section titled “Collections”Zeku reads src/content.config.ts (or .js, .mjs, or .mts) and offers every collection defined there. For each one, it uses:
- the loader’s
basefolder, so a collection can live anywhere, even inside another collection’s folder - the schema, for the fields each entry has
- the loader’s
pattern, which decides which files are entries, the same way Astro reads it: a file it skips, like one in a subfolder under*.mdor one an exclusion like!archive/**names, isn’t listed, audited, or given a URL. A file named_name.mdis the exception, since Zeku treats it as a draft of its collection, so it stays listed as a draft even when the pattern skips underscore files.
A collection of data, like one file loaded with file() or a folder of JSON or YAML files, has no pages to write, so it gets a button of its own on the dashboard instead. See Data collections.
A collection whose entries aren’t files in your content folder, such as one a loader fetches from an API or one loaded from src/pages, has nothing for Zeku to list or create, so it starts hidden on the dashboard, and its card in Settings > Content says where its entries come from.
When every collection loads from outside src/content, like src/posts and src/moments, Zeku opens the folder that holds them instead. A content config Zeku can’t read, such as one that builds its collections in a loop, counts as none: the content folder’s folders are read as collections, as below. A config from Astro 5 or earlier with no loaders at all also gets a collection for each folder of Markdown it doesn’t declare, since Astro builds those too.
Sites without content collections
Section titled “Sites without content collections”Some sites write their posts as Markdown pages in src/pages, or keep them in a folder with no content config at all. Zeku opens the folder that holds the Markdown, src/pages when that’s where it is, even beside a src/content that holds only data, and reads each of its folders of Markdown as a collection, whatever the folder is called. The pages at the folder’s root are a collection too, so a site that’s a single src/pages/index.md opens to a dashboard like any other. A site whose content config loads its collections from folders of their own isn’t opened in src/pages, even when it keeps a Markdown page there. With no schema to say what a field takes, a new page starts with the fields most of the folder’s pages carry, at a value that means the same as leaving each one out. A new page in src/pages also starts with the layout most of its collection’s pages name, since a Markdown page there only looks like the rest of your site when it names one. Change it, or clear it to leave it out, under New page layout in Settings > Content.
Field types
Section titled “Field types”Astro writes a JSON schema for each collection to .astro/collections/ whenever astro sync or astro dev runs. Zeku reads those files for exact field types, including which fields are required, and reads your config for the two helpers the JSON loses: image() and reference().
Astro 4 writes no JSON schema, and neither does a site that has never run astro sync. Zeku then reads the plain shapes from your config itself: text with its URL, email, pattern and length checks, numbers, true or false, dates, fixed choices, lists and objects, each required unless it’s optional or has a default. That’s enough for a new page to start with every field the schema requires. The build check still waits for a real schema before it calls a value wrong.
Zeku shows each entry’s URL on the dashboard, uses it for the site preview and the SEO audit, and writes it when you link to the entry. It works the URL out from the routes your site builds:
- It finds the dynamic route in
src/pagesthat renders the collection, such assrc/pages/blog/[...slug].astro, for the part before the entry. A route that gets its entries from a helper function, likegetAllPosts(), is followed into that function, through a tsconfig alias such as@/utils, a bare path likesrc/utilsthat tsconfig’sbaseUrlresolves, a default import, and an index file that only re-exports it. An optional segment such as[...lang]is left out for your default locale, and an entry in another locale gets its locale in front. Entries kept in locale folders, likeblog/en/andblog/fr/, get the same treatment when your routes serve them that way:blog/fr/post-1.mdat/fr/blog/post-1/, and the default locale’s at/blog/post-1/. A route that starts with a[locale]or[lang]folder counts as serving every locale under its code, and the default locale too when no other route serves it without one, so a page in no locale folder is then the default locale’s, as in/en/blog/first-post/. A route that takes a locale folder off each entry’s id in its code, likepost.id.replace('en/', ''), serves that locale without it. WithprefixDefaultLocale: truein astro.config’s i18n settings, entries kept in locale folders get the default locale’s code in front too, as in/en/blog/post-1/. - For the entry itself, the field the route names its pages by wins: a
slugfield in the frontmatter, used exactly as written, or another field such asabbrlinkwhen the route reads that one. A slug that starts with a locale folder, likede/my-post, puts that locale in front instead. - Otherwise it takes the file’s path inside the collection, drops the extension, and slugifies each part the way Astro does, so
My Post.mdbecomesmy-postandtrip/index.mdbecomestrip. Folders stay in the URL when the route builds it from the file’s path. A route that takes another name off the end of each id, likeentry.id.replace("/-index", ""), serves a folder’s-index.mdat the folder the same way.
A Markdown page in src/pages is at its file’s path, since Astro routes it by its name: src/pages/posts/hello.md is at /posts/hello/, whatever slug it sets.
Entries the route filters out, such as files whose names start with - on some themes, aren’t pages. Neither is anything in a collection no route serves, or in any collection when none of the pages in src/pages serves a single entry, as on a portfolio that lists its projects on its home page and nowhere else. Their cards say Not a page. A route that builds one page per group, such as one per bookmark type from new Set(...), and renders no entry, is a list rather than the entries’ route. Whether a URL ends in a slash follows trailingSlash and build.format in astro.config, and the site preview corrects it from what your dev server actually answers. A base in astro.config goes in front of every URL, even when your config sets it from another file.
When Zeku works out a URL wrong, correct it per collection in Settings > Content, with URL, Slug field, Keep folders in URLs, Locale field, Locale folders, Default locale, Default locale in URLs too and Not pages.
Copy live URL and Open on the live site put that URL after your site’s address, site in astro.config, followed into the file your config imports it from. When Zeku can’t read it, or reads it wrong, set Live site address in Settings > Content, with the path your site is served under if it has one, like https://name.github.io/repo. Live page addresses sets the form build.format gives them, such as /posts/my-post.html.
A collection with no route of its own has no URL in Zeku either, since your site doesn’t publish its entries as pages. A collection whose loader has its own generateId function keeps the file path as written, since Zeku can’t run that function.
The dashboard’s collections
Section titled “The dashboard’s collections”Every collection shows on the dashboard, with one exception: a collection that has no route of its own and lives inside another collection’s folder starts hidden, because it’s a detail of that collection rather than something you browse. Show or hide any collection in Settings > Content.
The dashboard opens on the collection that looks most like a blog. Choose another under Opens on in Settings > Content. That choice stays on your computer, and New starts in that collection too when no collection is on screen.
What Zeku stores in your project
Section titled “What Zeku stores in your project”Choices that describe the project, not your computer, go in a .zeku folder inside the folder Zeku opened, usually your content folder:
| File | Holds |
|---|---|
.zeku/config.json |
Which collections and folders you’ve shown or hidden, how each collection’s dashboard cards show covers and fields, and your corrections to what Zeku read from your site, such as the Markdown it renders, the form links take, its live address, and whether renames write redirects |
.zeku/types.json |
Field types you’ve set by hand |
.zeku/snippets/ |
CSS snippets |
Zeku creates these only when you change one of those choices, writes them the same way on every computer so they merge cleanly, and never puts anything specific to your machine in them. Commit the folder, and the choices follow the project.