CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-astro

Astro is a modern site builder with web best practices, performance, and DX front-of-mind.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

content-collections.mddocs/

Content Collections

Type-safe content management with schema validation, multiple data sources, and runtime querying.

Define Collection

function defineCollection<S extends BaseSchema>(config: CollectionConfig<S>): CollectionConfig<S>;

interface CollectionConfig<S> {
  type?: 'content' | 'data' | 'content_layer';  // default: 'content'
  schema?: S | ((context: SchemaContext) => S);
  loader?: Loader | (() => Array<DataType> | Promise<Array<DataType>>);
}

interface SchemaContext {
  image: ImageFunction;
}
import { defineCollection, z } from 'astro:content';

const blog = defineCollection({
  type: 'content',
  schema: z.object({
    title: z.string(),
    pubDate: z.date(),
    tags: z.array(z.string())
  })
});

export const collections = { blog };

Loaders

Glob Loader

function glob(options: GlobOptions): Loader;

interface GlobOptions {
  pattern: string | string[];
  base?: string | URL;
  generateId?: (options: { entry: string; base: URL; data: Record<string, unknown>; }) => string;
}
import { glob } from 'astro:content';

const docs = defineCollection({
  loader: glob({ pattern: '**/*.md', base: './docs' }),
  schema: z.object({ title: z.string() })
});

File Loader

function file(fileName: string, options?: { parser?: (text: string) => any }): Loader;
import { file } from 'astro:content';

const products = defineCollection({
  loader: file('products.json'),
  schema: z.object({ name: z.string(), price: z.number() })
});

Custom Loader Context

interface LoaderContext {
  collection: string;
  store: DataStore;
  logger: AstroIntegrationLogger;
  config: AstroConfig;
  parseData<T>(props: { id: string; data: T; filePath?: string; }): Promise<T>;
  renderMarkdown(content: string): Promise<{ html: string; metadata: { headings: MarkdownHeading[]; imagePaths: string[]; }; }>;
  generateDigest(data: Record<string, unknown> | string): string;
}

Runtime Querying

Get Collection

function getCollection<C>(collection: C, filter?: (entry: Collections[C]) => boolean): Promise<Array<Collections[C]>>;
import { getCollection } from 'astro:content';

const allPosts = await getCollection('blog');
const published = await getCollection('blog', (p) => !p.data.draft);
const tagged = await getCollection('blog', (p) => p.data.tags.includes('tutorial'));

Get Entry

function getEntry<C>(collection: C, id: string): Promise<Collections[C] | undefined>;
function getEntry(lookup: { collection: string; id?: string; slug?: string; }): Promise<Entry | undefined>;
const post = await getEntry('blog', 'my-post');
const page = await getEntry({ collection: 'docs', slug: 'getting-started' });

Get Entries (batch)

function getEntries(entries: Array<{ collection: string; id?: string; slug?: string; }>): Promise<Array<Entry>>;
const related = await getEntries([
  { collection: 'blog', id: 'post-1' },
  { collection: 'blog', id: 'post-2' }
]);

Render Entry

function render(entry: ContentEntry): Promise<{ Content: AstroComponent; headings: MarkdownHeading[]; remarkPluginFrontmatter: Record<string, any>; }>;
const post = await getEntry('blog', 'my-post');
const { Content, headings } = await render(post);

Live Collections

Define Live Collection

function defineLiveCollection<L, S>(config: { type?: 'live'; schema?: S; loader: L; }): LiveCollectionConfig<L, S>;

interface LiveLoader {
  loadCollection(collection: string): Promise<Array<Entry>>;
  loadEntry(collection: string, id: string): Promise<Entry | undefined>;
}
// src/live.config.ts
import { defineLiveCollection } from 'astro:content';

export const collections = {
  posts: defineLiveCollection({
    loader: myLiveLoader,
    schema: z.object({ title: z.string() })
  })
};

Query Live Collections

function getLiveCollection(collection: string, filter?: Record<string, any>): Promise<{ data: LiveDataEntry[]; cacheHint?: CacheHint; }>;
function getLiveEntry(collection: string, lookup: string | Record<string, any>): Promise<{ data: LiveDataEntry; cacheHint?: CacheHint; }>;

Error Handling

class LiveCollectionError extends Error {
  readonly collection: string;
  static is(error: unknown): error is LiveCollectionError;
}

class LiveEntryNotFoundError extends LiveCollectionError {
  static is(error: unknown): error is LiveEntryNotFoundError;
}

class LiveCollectionValidationError extends LiveCollectionError {
  static is(error: unknown): error is LiveCollectionValidationError;
}
import { getLiveEntry, LiveEntryNotFoundError } from 'astro:content';

try {
  const result = await getLiveEntry('products', { sku: 'ABC-123' });
} catch (error) {
  if (LiveEntryNotFoundError.is(error)) {
    console.error(`Entry not found in ${error.collection}`);
  }
}

Schema Helpers

Reference Schema

function reference(collection: string): ZodType;
const authors = defineCollection({
  type: 'data',
  schema: z.object({ name: z.string() })
});

const blog = defineCollection({
  schema: z.object({
    title: z.string(),
    author: reference('authors'),
    related: z.array(reference('blog'))
  })
});

Image Schema

const schema = ({ image }) => z.object({
  title: z.string(),
  coverImage: image()
});

Entry Types

interface ContentEntry<T = any> {
  id: string; slug: string; body: string; collection: string;
  data: T;
  render(): Promise<RenderResult>;
}

interface DataEntry<T = any> {
  id: string; collection: string; data: T;
}

Templates

Basic Collection

// src/content/config.ts
import { defineCollection, z } from 'astro:content';

export const collections = {
  blog: defineCollection({
    type: 'content',
    schema: z.object({
      title: z.string(),
      description: z.string(),
      pubDate: z.date(),
      tags: z.array(z.string())
    })
  })
};

Load and Render

import { getCollection, render } from 'astro:content';

const posts = await getCollection('blog');
const { Content, headings } = await render(posts[0]);

Cross-References

const blog = defineCollection({
  schema: z.object({
    author: reference('authors'),
    relatedPosts: z.array(reference('blog'))
  })
});

Troubleshooting

  • Schema validation: Use z.optional() for optional fields
  • Live collections: Define in src/live.config.ts, not src/content/config.ts
  • References: Referenced collections must be defined first
  • Loader types: Use type: 'content_layer' with custom loaders

docs

assets.md

cli-and-build.md

configuration.md

container.md

content-collections.md

content-loaders.md

dev-toolbar.md

environment.md

i18n.md

index.md

integrations.md

middleware.md

server-actions.md

ssr-and-app.md

transitions.md

tile.json