Skip to content
qino

Since 0.1.0

defineCollection

Define a flat directory of entries that share one schema.

Defines a collection: a flat directory of files with one extension and one schema. Returns getters for listing, reading, and enumerating slugs.

qino/collections/posts.ts
import { z } from "zod";

import qino from "../";
import { authorCollection } from "./authors";

export const postCollection = qino.defineCollection({
  directory: "/posts",
  extension: ".md",
  schema: z.object({
    title: z.string(),
    author: z.string(),
    draft: z.boolean(),
    markdown: z.string(),
  }),
  relations: { author: authorCollection },
  views: (view) => ({
    default: view({ filter: (post) => !post.draft }),
    detail: view({ resolveRelations: 1 }),
  }),
});

Signature

@qino/cms
qino.defineCollection(params: {
  directory: `/${string}`;
  extension: ".md" | ".mdx" | ".markdown" | ".json";
  schema: StandardSchemaV1<unknown, Record<string, unknown>>;
  relations?: Record<RelationPath, Primitive | (() => Primitive)>;
  views?: (view: ViewHelper) => Record<string, View> & { default: View };
}): Collection;

Parameters

NameTypeRequiredDefaultDescription
directory`/${string}`yesDirectory under contentFolder. Must start with /. Flat: nested files are ignored
extension".md" | ".mdx" | ".markdown" | ".json"yesOnly files with this extension are entries
schemaStandard Schema object validatoryesSynchronous. Receives frontmatter plus markdown, or the JSON object. May not declare _meta
relationsRecord<path, primitive | () => primitive>no{}JSON paths into the schema output mapped to target primitives. [*] marks an array hop
views(view) => { default: View; [name]: View }noFactory run once at definition. Must return a default view made with the helper

resolveRelations, augment, filter, and sort are rejected at the root. Put them inside a view. See view.

Returns

A Collection with three getters:

Use Infer<typeof postCollection> to name the entry types. See Infer.

Throws

At definition time:

  • Configure "<key>" inside views.default or a custom view, not at the root.
  • Configure views with views: (view) => ({ default: view({ ... }) }). Object-form views are no longer supported.
  • The views factory must synchronously return an object of named views.
  • The views factory must return a "default" view created with view({ ... }).
  • View "<name>" must be created with view({ ... }).

See also

In this section