Skip to main content

Overview

Content Collections provide type-safe, validated content management in Astro. The project uses collections for blog posts and promotional content.

Configuration

Content collections are defined in src/content.config.ts:
import { glob } from 'astro/loaders';
import { defineCollection, z } from 'astro:content';

// Blog collection schema
const blog = defineCollection({
  loader: glob({ base: './src/content/blog', pattern: '**/*.{md,mdx}' }),
  schema: z.object({
    title: z.string(),
    description: z.string(),
    pubDate: z.coerce.date(),
    draft: z.boolean(),
    tags: z.array(z.string()).optional(),
    heroImage: z.string().optional(),
    publisher: z.string().optional(),
  }),
});

// Promo schema for promotional pages
const promoSchema = z.object({
  titulo: z.string(),
  subtitulo: z.string(),
  precio: z.string(),
  destacado: z.string(),
  backgroundImage: z.string(),
  detalles: z.array(z.string()),
  link: z.string(),
  tituloMain: z.string(),
  parrafosMain: z.array(z.string()),
  imagenMain: z.string(),
  detallesSideBar: z.array(
    z.object({
      icono: z.string(),
      titulo: z.string(),
      contenido: z.string(),
    })
  ),
});

export const collections = {
  blog,
  promoSingle: defineCollection({
    loader: glob({ base: './src/content/promoSingle', pattern: '**/*.{md,mdx,json}' }),
    schema: promoSchema
  }),
  promoPro: defineCollection({
    loader: glob({ base: './src/content/promoPro', pattern: '**/*.{md,mdx,json}' }),
    schema: promoSchema
  }),
  promoTienda: defineCollection({
    loader: glob({ base: './src/content/promoTienda', pattern: '**/*.{md,mdx,json}' }),
    schema: promoSchema
  }),
};

Collections

Blog Collection

Location: src/content/blog/ Schema:
FieldTypeRequiredDescription
titlestringYesBlog post title
descriptionstringYesMeta description
pubDatedateYesPublication date
draftbooleanYesDraft status
tagsstring[]NoPost tags
heroImagestringNoHero image path
publisherstringNoPublisher name
Example:
---
title: "Cuánto Cuesta Crear Una Página Web"
description: "Guía completa de precios para crear páginas web en 2026"
pubDate: 2026-01-15
draft: false
tags: ["precios", "desarrollo web"]
heroImage: "/img/blog/costes-web.webp"
publisher: "Arte y Web Creaciones"
---

Your content here...

Promotional Collections

Three collections for different service tiers:
  • promoSingle - Single page websites
  • promoPro - Professional multi-page websites
  • promoTienda - E-commerce stores
Location: src/content/promoSingle/, src/content/promoPro/, src/content/promoTienda/

Using Collections

Query All Entries

import { getCollection } from 'astro:content';

// Get all blog posts
const posts = await getCollection('blog');

// Filter published posts
const publishedPosts = await getCollection('blog', ({ data }) => {
  return data.draft !== true;
});

// Sort by date
const sortedPosts = posts.sort(
  (a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf()
);

Query Single Entry

import { getEntry } from 'astro:content';

const post = await getEntry('blog', 'cuanto-cuesta-una-pagina-web');

Render Content

---
import { getEntry } from 'astro:content';

const post = await getEntry('blog', Astro.params.slug);
const { Content } = await post.render();
---

<article>
  <h1>{post.data.title}</h1>
  <Content />
</article>

Type Safety

Content Collections provide full TypeScript support:
import type { CollectionEntry } from 'astro:content';

type BlogPost = CollectionEntry<'blog'>;

function formatPost(post: BlogPost) {
  return {
    title: post.data.title,
    date: post.data.pubDate.toLocaleDateString('es-ES'),
  };
}

Validation

Zod schemas automatically validate frontmatter:
---
title: "My Post"
# Error: description is required
draft: false
pubDate: 2026-01-15
---
Build will fail if any content doesn’t match the schema. This ensures data integrity.

Adding New Collections

  1. Create directory: src/content/your-collection/
  2. Define schema in src/content.config.ts
  3. Export in collections object
const myCollection = defineCollection({
  loader: glob({ base: './src/content/my-collection', pattern: '**/*.md' }),
  schema: z.object({
    title: z.string(),
    // ... other fields
  }),
});

export const collections = {
  // ... existing collections
  myCollection,
};

Build docs developers (and LLMs) love