Astro Content Collections: do conceito à validação de Schema

A página inicial do blog caiu porque o campo publishDate de um post estava no formato errado. Levei meia hora procurando o arquivo até descobrir o problema: a data estava escrita como 2024/12/01, e não 2024-12-01. Isso aconteceu em um blog com apenas 30 posts. Com centenas deles, conferir todos os arquivos manualmente sempre que um campo novo for adicionado não é viável.
Content Collections resolve esse problema: o Astro passa a detectar erros no conteúdo da mesma forma que o TypeScript detecta erros no código. Depois que o Schema é configurado, o editor também oferece sugestões, sem que você precise consultar a documentação para lembrar o nome de cada campo. A seguir, você verá o que é Content Collections, como escrever o arquivo de configuração e como usar a validação de Schema.
O que é Content Collections e por que usar esse recurso?
Talvez você esteja pensando: Content Collections não é apenas uma forma de organizar pastas com arquivos Markdown? Eu não poderia simplesmente criar uma pasta blog/ dentro de src/pages/ e implementar o blog do mesmo jeito?
Sim, em termos de funcionalidade. O problema é que essa abordagem não oferece segurança de tipos.
Na abordagem tradicional, o frontmatter do Markdown seria assim:
---
title: "Título do meu blog"
date: "2024-12-01"
tags: ["Astro", "Tutorial"]
---
Conteúdo do post...
Parece correto, certo? Agora considere estes cenários:
- Em um post, você escreve
tagem vez detags, esquecendo o s - Você usa o formato de data
12/01/2024em vez de2024-12-01 - Você adiciona um campo
author, mas esquece de incluí-lo em alguns posts antigos
O Astro não avisa sobre esses erros com antecedência. Você só descobre o problema em tempo de execução, quando a renderização da página falha.
Content Collections existe justamente para resolver isso. Em essência, é um sistema de gerenciamento de conteúdo com segurança de tipos. Pense nele como uma forma de adicionar verificação de tipos do TypeScript aos arquivos Markdown.
Na prática, Content Collections oferece estes recursos:
- Validação de Schema: define os tipos e a estrutura dos campos do frontmatter e gera um erro imediato quando algo não corresponde à definição
- Geração automática de tipos: cria tipos TypeScript a partir do Schema, com sugestões inteligentes no editor
- API de consulta unificada: permite consultar o conteúdo com métodos como
getCollection(), que retornam dados tipados - Otimização de desempenho: a Content Layer API introduzida no Astro 5.0 acelera as consultas
Em outras palavras, a abordagem tradicional é livre, mas insegura; Content Collections impõe regras e oferece confiabilidade. O tempo investido na configuração do Schema evita 99% dos erros mais básicos.
Sinceramente, hoje uso Content Collections em todos os meus projetos Astro. Você configura uma vez e aproveita os benefícios durante todo o projeto.
Configuração prática de Content Collections
Terminada a teoria, vamos configurar o recurso. O processo tem três etapas: criar os diretórios, escrever a configuração e criar o conteúdo.
Primeira etapa: criar os diretórios
Content Collections exige que o conteúdo fique dentro de src/content/. Esse é um diretório reservado pelo Astro desde a versão 2.0 e destinado às coleções de conteúdo.
A estrutura fica mais ou menos assim:
src/
├── content/
│ ├── blog/ # Coleção do blog
│ │ ├── post-1.md
│ │ └── post-2.md
│ └── docs/ # Coleção da documentação
│ ├── guide-1.md
│ └── guide-2.md
├── content.config.ts # Arquivo de configuração (observe a localização)
└── pages/
└── ...
Atenção: o arquivo de configuração é src/content.config.ts (ou .js, .mjs) e não fica dentro do diretório content/. Quando comecei, coloquei o arquivo no lugar errado e levei um bom tempo para encontrar a causa do problema.
Cada subdiretório representa uma coleção. Por exemplo, src/content/blog/ é a coleção blog, enquanto src/content/docs/ é a coleção docs.
Segunda etapa: escrever o arquivo de configuração
Crie src/content.config.ts, o arquivo central de Content Collections:
// src/content.config.ts
import { defineCollection, z } from 'astro:content';
// Define a coleção blog
const blogCollection = defineCollection({
type: 'content', // Tipo content para arquivos Markdown/MDX
schema: z.object({
title: z.string(), // Título (obrigatório)
description: z.string(), // Descrição (obrigatória)
pubDate: z.coerce.date(), // Data de publicação (convertida automaticamente em Date)
tags: z.array(z.string()).optional(), // Array de tags (opcional)
draft: z.boolean().default(false), // Estado de rascunho (false por padrão)
}),
});
// Exporta o objeto collections
export const collections = {
'blog': blogCollection, // A chave corresponde ao nome do diretório
};
O código pode parecer um pouco complexo, então vamos dividir cada parte:
defineCollection(): define a configuração de uma coleçãotype: 'content': informa que a coleção contém arquivos Markdown/MDXschema: usa Zod, uma biblioteca de validação, para definir a estrutura do frontmatter- Objeto
collections: exporta as configurações; cada chave deve ser igual ao nome do diretório correspondente
O ponto principal está em schema. Cada campo recebe um tipo com z.xxx():
z.string(): stringz.coerce.date(): converte automaticamente uma string em um objeto Datez.array(z.string()): array de strings.optional(): torna o campo opcional.default(false): define um valor padrão
Terceira etapa: criar um arquivo de conteúdo
Depois da configuração, você pode criar um arquivo Markdown em src/content/blog/:
---
title: "Introdução ao Astro Content Collections"
description: "Aprenda a configurar e usar Content Collections"
pubDate: "2024-12-01"
tags: ["Astro", "Tutorial"]
---
Este é o conteúdo do post...
Se o frontmatter estiver de acordo com o Schema, o Astro poderá analisá-lo normalmente. Quando um campo é incompatível, como um pubDate em formato incorreto, o Astro exibe um erro já durante a compilação.
Consultar dados em uma página
Depois de configurar a coleção, você pode consultar o conteúdo em qualquer arquivo Astro:
---
// src/pages/blog/index.astro
import { getCollection } from 'astro:content';
// Busca todos os posts do blog
const allPosts = await getCollection('blog');
// Remove os rascunhos (draft: true)
const publishedPosts = allPosts.filter(post => !post.data.draft);
---
<ul>
{publishedPosts.map(post => (
<li>
<a href={`/blog/${post.slug}`}>
{post.data.title}
</a>
<p>{post.data.description}</p>
</li>
))}
</ul>
Observe que post.data contém os dados do frontmatter e tem tipagem completa do TypeScript. Quando você digita post.data. no VS Code, o editor sugere automaticamente campos como title, description e pubDate.
Essa é a principal vantagem de Content Collections: segurança de tipos e sugestões inteligentes no editor, que melhoram bastante a experiência de desenvolvimento.
Validação de Schema em detalhes
Na seção anterior, usamos tipos básicos como z.string() e z.coerce.date(). A validação de Schema, porém, oferece muito mais. Agora vamos explorar outros recursos do Zod.
Referência rápida de tipos básicos
Comece pelos tipos mais usados:
import { z } from 'astro:content';
z.string() // String
z.number() // Número
z.boolean() // Booleano
z.date() // Objeto Date
z.coerce.date() // Converte automaticamente uma string em Date
z.array(z.string()) // Array de strings
z.enum(['draft', 'published']) // Enumeração (aceita apenas os valores definidos)
z.coerce.date() é especialmente útil. No frontmatter de um arquivo Markdown, as datas são escritas como strings, por exemplo, "2024-12-01". Se você usar z.date(), ocorrerá um erro porque esse tipo exige um objeto Date. Já z.coerce.date() faz a conversão automaticamente e evita esse trabalho.
Campos opcionais e valores padrão
Nem todos os campos precisam ser obrigatórios. Alguns posts podem não precisar de tags; nesse caso, use .optional():
schema: z.object({
title: z.string(), // Obrigatório
tags: z.array(z.string()).optional(), // Opcional
draft: z.boolean().default(false), // Com valor padrão
})
.default() é útil porque o Astro preenche automaticamente o valor padrão quando o campo não existe no frontmatter.
Uso avançado: validação de imagens
O Astro também oferece o tipo image(), específico para validar caminhos de imagens:
import { defineCollection, z } from 'astro:content';
const blogCollection = defineCollection({
schema: ({ image }) => z.object({ // Aqui usamos a forma de função
title: z.string(),
cover: image(), // Validação do caminho da imagem
}),
});
image() verifica se o caminho aponta para um arquivo de imagem válido e aceita caminhos relativos. Esse recurso é particularmente útil para exibir capas na página inicial de um blog.
Referenciar outras coleções com z.reference()
Às vezes, o conteúdo tem relações internas. Um post pode pertencer a uma categoria que, por sua vez, também é uma coleção. Nesse caso, use z.reference():
// Define a coleção de categorias
const categoryCollection = defineCollection({
schema: z.object({
name: z.string(),
slug: z.string(),
}),
});
// A coleção blog referencia uma categoria
const blogCollection = defineCollection({
schema: z.object({
title: z.string(),
category: z.reference('category'), // Referencia a coleção category
}),
});
export const collections = {
'category': categoryCollection,
'blog': blogCollection,
};
No frontmatter do post, o campo category precisa conter apenas o nome do arquivo da categoria, sem a extensão:
---
title: "Meu blog"
category: "tech" # Referencia src/content/category/tech.md
---
O Astro verifica automaticamente se a categoria existe, mantendo também a segurança de tipos.
Objetos complexos aninhados
Se o frontmatter tiver uma estrutura mais complexa, você pode aninhar objetos:
schema: z.object({
title: z.string(),
author: z.object({
name: z.string(),
email: z.string().email(), // Valida o formato do e-mail
avatar: z.string().url(), // Valida o formato da URL
}),
seo: z.object({
keywords: z.array(z.string()),
description: z.string().max(160), // Limita o tamanho máximo
}).optional(),
})
O frontmatter correspondente seria:
---
title: "Título do post"
author:
name: "Zhang San"
email: "[email protected]"
avatar: "https://example.com/avatar.jpg"
seo:
keywords: ["Astro", "Tutorial"]
description: "Este é um tutorial sobre Astro"
---
A segurança de tipos na prática: inferência automática do TypeScript
Depois que o Schema é configurado, o Astro gera automaticamente os tipos TypeScript. Ao consultar os dados no código, o editor oferece todas as sugestões:
import { getCollection } from 'astro:content';
const posts = await getCollection('blog');
posts.forEach(post => {
// O editor sugere todos os campos de post.data
console.log(post.data.title); // ✅ Tipo: string
console.log(post.data.pubDate); // ✅ Tipo: Date
console.log(post.data.tags); // ✅ Tipo: string[] | undefined
console.log(post.data.notExist); // ❌ Erro de compilação: o campo não existe
});
Esse é um dos melhores aspectos de Content Collections. Você não precisa escrever definições de tipos manualmente; o Astro as gera a partir do Schema, com precisão.
getEntry() versus getCollection()
Para concluir, vale distinguir as duas APIs de consulta:
getCollection('blog'): busca todo o conteúdo da coleçãogetEntry('blog', 'my-post'): busca um único item pelo slug informado
A consulta individual é mais eficiente e adequada às páginas de detalhes:
---
// src/pages/blog/[slug].astro
import { getEntry } from 'astro:content';
const { slug } = Astro.params;
const post = await getEntry('blog', slug);
if (!post) {
return Astro.redirect('/404');
}
const { Content } = await post.render();
---
<article>
<h1>{post.data.title}</h1>
<Content />
</article>
Sinceramente, a sintaxe do Zod também me confundiu no começo. Depois de usá-la algumas vezes, ela fica familiar, e as mensagens de erro do Zod são claras o suficiente para facilitar a investigação.
Erros comuns e soluções
Ao configurar Content Collections, é normal encontrar alguns erros. Estes são os problemas que apareceram com mais frequência nos meus projetos e como resolvê-los.
Erro 1: MarkdownContentSchemaValidationError
Esse é o erro mais comum. Ele indica que o frontmatter não corresponde à definição do Schema. A mensagem pode ser parecida com esta:
blog → my-post.md frontmatter does not match collection schema.
- "title" is required
- "pubDate" must be a valid date
Como interpretar esse erro?
O Astro informa claramente qual arquivo (my-post.md) e quais campos (title, pubDate) estão com problemas.
Causas comuns e soluções:
-
Campo ausente: o Schema define um campo obrigatório, mas ele não está no frontmatter
- Solução: adicione o campo ausente ou marque-o com
.optional()no Schema
- Solução: adicione o campo ausente ou marque-o com
-
Nome de campo digitado incorretamente: por exemplo,
publishDateem vez depubDate- Solução: padronize os nomes e use o preenchimento automático do editor
-
Tipo incompatível: por exemplo, o Schema exige
z.number(), mas o frontmatter contém uma string- Solução: confira o formato do valor
Erro 2: InvalidContentEntryFrontmatterError
Esse erro indica que o formato do próprio frontmatter está incorreto. Em outras palavras, há um erro de sintaxe YAML que impede até mesmo a análise do arquivo.
Uma causa comum seria:
---
title: "Meu título
description: "As aspas do título não foram fechadas"
---
Para corrigir, verifique a sintaxe YAML, em especial aspas, dois-pontos e recuo. Uma extensão de editor com validação de YAML também ajuda.
Erro 3: formato de data
Já caí nessa armadilha várias vezes. Se você usar z.date() em vez de z.coerce.date(), o Astro exigirá que a data do frontmatter seja um objeto Date, e não uma string. Mas, no YAML, a data é escrita como texto.
Solução: use z.coerce.date() no Schema para converter a string automaticamente em um objeto Date:
// ❌ Incorreto: exige um objeto Date, mas o frontmatter contém uma string
pubDate: z.date()
// ✅ Correto: converte automaticamente a string em Date
pubDate: z.coerce.date()
Tratar dados legados com .passthrough()
Se o blog já tiver muitos posts antigos, talvez os campos de frontmatter não estejam padronizados. Nesse caso, .passthrough() pode flexibilizar temporariamente a validação:
schema: z.object({
title: z.string(),
// ... Outros campos
}).passthrough() // Permite campos adicionais que não foram definidos
Essa é apenas uma solução provisória. No longo prazo, é melhor padronizar a estrutura do frontmatter.
Como organizar várias coleções
Se o site reúne blog, documentação, estudos de caso e outros tipos de conteúdo, você pode criar várias coleções:
src/content/
├── blog/
├── docs/
└── case-studies/
Depois, defina cada coleção separadamente em content.config.ts:
const blogCollection = defineCollection({ /* ... */ });
const docsCollection = defineCollection({ /* ... */ });
const caseStudiesCollection = defineCollection({ /* ... */ });
export const collections = {
'blog': blogCollection,
'docs': docsCollection,
'case-studies': caseStudiesCollection,
};
Cada coleção pode ter seu próprio Schema sem interferir nas demais.
Boas práticas de design de Schema
Estas são as práticas que funcionaram melhor para mim:
- Mantenha poucos campos obrigatórios: exija apenas o necessário e use
.optional()ou.default()nos demais - Use
z.coerce.date()para datas: isso evita conversões manuais - Use camelCase nos nomes dos campos:
pubDatecombina melhor com as convenções do JavaScript do quepub_date - Divida objetos complexos: se o frontmatter ficar complicado, considere criar várias coleções relacionadas por
z.reference() - Escreva comentários claros: explique no Schema a finalidade de cada campo para a equipe
Checklist para investigar problemas
Quando encontrar um erro, confira estes itens na ordem:
- O diretório
src/content/existe? - O arquivo
src/content.config.tsestá no local correto, fora decontent/? - No objeto
collectionsexportado pelo Schema, as chaves correspondem aos nomes dos diretórios? - A sintaxe YAML do frontmatter está correta, incluindo aspas, dois-pontos e recuo?
- Todos os campos obrigatórios estão preenchidos?
- Os tipos dos campos correspondem à definição do Schema?
Esses problemas podem parecer complexos, mas as mensagens de erro do Astro são claras. Se você ler os detalhes com atenção, normalmente encontra a causa rapidamente.
Conclusão
Depois de tudo isso, podemos voltar às três dúvidas iniciais.
O que é Content Collections? É uma forma de adicionar verificação de tipos do TypeScript ao conteúdo Markdown. Assim, o Astro encontra erros durante a compilação, antes que eles derrubem a página em tempo de execução.
Como escrever o arquivo de configuração? Lembre-se das três etapas: criar o diretório src/content/, criar src/content.config.ts e definir o Schema com defineCollection() e Zod. Cada chave deve ser igual ao nome do diretório correspondente.
Como usar a validação de Schema? Domine os tipos básicos, como z.string(), z.coerce.date() e z.array(), use .optional() e .default() quando necessário e leia as mensagens do Astro ao investigar erros.
Content Collections é um dos recursos mais úteis do Astro. A configuração exige algum tempo no início, mas depois poupa inúmeras horas de investigação. As sugestões inteligentes do editor também tornam a experiência de programação muito melhor.
Próximos passos
Se você quiser testar Content Collections agora, siga estas sugestões:
- Use desde o início em projetos novos: configure Content Collections ao criar o projeto Astro e estabeleça as regras logo no começo
- Migre projetos antigos aos poucos: use
.passthrough()para manter o conteúdo atual funcionando e padronize gradualmente a estrutura do frontmatter - Consulte a documentação oficial: quando surgir uma dúvida, veja a documentação oficial do Astro, que traz a referência completa da API
Content Collections não é difícil, mas exige prática. Ler tutoriais ajuda; escrever o arquivo de configuração por conta própria ajuda muito mais. Faça um teste e veja como a segurança de tipos muda o fluxo de trabalho.
Configuração completa do Astro Content Collections
Etapas para configurar Content Collections do zero até a validação de Schema e criar um sistema de conteúdo com segurança de tipos
⏱️ Estimated time: 30 min
- 1
Step 1: Criar a estrutura de diretórios
Crie o diretório src/content/ na raiz do projeto:
• Diretório reservado pelo Astro desde a versão 2.0
• Crie subdiretórios dentro de content/ para representar coleções, como blog/ e docs/
• Cada subdiretório corresponde a uma coleção
Atenção: o arquivo de configuração src/content.config.ts fica em src/, e não dentro de content/. - 2
Step 2: Criar o arquivo de configuração
Crie o arquivo src/content.config.ts:
1. Importe as dependências:
import { defineCollection, z } from 'astro:content'
2. Defina a configuração da coleção:
const blogCollection = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
description: z.string(),
pubDate: z.coerce.date(),
tags: z.array(z.string()).optional(),
draft: z.boolean().default(false)
})
})
3. Exporte o objeto collections:
export const collections = { 'blog': blogCollection }
Atenção: a chave deve ser igual ao nome do diretório - 3
Step 3: Criar um arquivo de conteúdo
Crie um arquivo Markdown em src/content/blog/:
O frontmatter deve seguir o Schema definido:
• title (string obrigatória)
• description (string obrigatória)
• pubDate (data no formato '2024-12-01'; z.coerce.date() faz a conversão automática)
• tags (array opcional de strings)
• draft (booleano opcional, false por padrão)
Se algum campo não corresponder ao Schema, o Astro exibirá um erro durante a compilação. - 4
Step 4: Consultar dados em uma página
Importe getCollection em um arquivo Astro:
import { getCollection } from 'astro:content'
Busque todos os posts do blog:
const allPosts = await getCollection('blog')
Filtre os rascunhos:
const publishedPosts = allPosts.filter(post => !post.data.draft)
Use os dados:
• post.data conta com tipagem completa do TypeScript
• O editor sugere automaticamente campos como title, description e pubDate
• Para consultar um único post, getEntry('blog', slug) é mais eficiente - 5
Step 5: Configurar Schemas avançados
Validação de imagens:
schema: ({ image }) => z.object({
cover: image()
})
Referência a outra coleção:
z.reference('category')
Objetos complexos aninhados:
z.object({
author: z.object({
name: z.string(),
email: z.string().email(),
avatar: z.string().url()
})
})
Tratamento de dados legados:
.passthrough() permite campos adicionais que não foram definidos
Cenários com várias coleções:
defina blog, docs, case-studies e outras coleções separadamente no objeto collections - 6
Step 6: Investigar erros comuns
MarkdownContentSchemaValidationError: verifique campos ausentes (adicione o campo ou use .optional()), nomes digitados incorretamente (padronize os nomes) e tipos incompatíveis (confira o formato do valor). InvalidContentEntryFrontmatterError: verifique a sintaxe YAML, incluindo aspas, dois-pontos e recuo. Problemas com datas: use z.coerce.date(), não z.date(). Checklist: o diretório content/ existe, content.config.ts está no local correto, as chaves de collections correspondem aos nomes dos diretórios, o YAML está válido, todos os campos obrigatórios foram preenchidos e os tipos correspondem ao Schema.
FAQ
O que é Content Collections e por que usar esse recurso?
A abordagem tradicional, criando uma pasta blog/ diretamente em src/pages/, não oferece segurança de tipos e facilita problemas como:
• Erros de digitação em campos, como tags escrito como tag
• Formatos de data incorretos, como 12/01/2024 em vez de 2024-12-01
• Campos novos que não foram adicionados aos posts antigos
• O Astro não avisa antes; o problema só aparece quando a página falha em tempo de execução
Content Collections oferece:
1) Validação de Schema, com tipos e estrutura definidos para o frontmatter e erro imediato em caso de incompatibilidade
2) Geração automática de tipos TypeScript com base no Schema e sugestões no editor
3) Uma API de consulta unificada, com métodos como getCollection() que retornam dados tipados
4) Otimização de desempenho com a Content Layer API do Astro 5.0
A abordagem tradicional é livre, mas insegura; Content Collections impõe regras e oferece confiabilidade. Uma única configuração beneficia o projeto inteiro.
Como configurar Content Collections do início ao fim?
1) Criar os diretórios:
• Crie src/content/ na raiz do projeto, um diretório reservado pelo Astro desde a versão 2.0
• Dentro de content/, crie subdiretórios para as coleções, como blog/ e docs/; cada subdiretório representa uma coleção
2) Escrever o arquivo de configuração:
• Crie src/content.config.ts, fora do diretório content/
• Importe defineCollection e z
• Defina a coleção: type: 'content' representa arquivos Markdown/MDX, e schema usa Zod para definir a estrutura do frontmatter
• Exporte o objeto collections; a chave deve corresponder ao diretório, como 'blog': blogCollection
3) Criar o conteúdo:
• Crie um arquivo Markdown em src/content/blog/
• O frontmatter deve seguir o Schema; caso contrário, o Astro exibirá um erro durante a compilação
Como usar a validação de Schema e quais são os tipos mais comuns?
• z.string() para strings
• z.number() para números
• z.boolean() para booleanos
• z.date() para objetos Date
• z.coerce.date() para converter strings em Date automaticamente, algo muito útil porque datas no YAML são escritas como texto
• z.array(z.string()) para arrays de strings
• z.enum(['draft', 'published']) para enumerações
Campos opcionais e valores padrão:
• .optional() torna o campo opcional
• .default(false) define um valor padrão
Recursos avançados:
• image() valida caminhos de imagem: schema: ({ image }) => z.object({ cover: image() })
• z.reference('category') referencia outra coleção
• Objetos complexos podem ser aninhados: z.object({ author: z.object({ name: z.string(), email: z.string().email() }) })
Depois que o Schema é configurado, o Astro gera automaticamente os tipos TypeScript. O editor passa a oferecer sugestões completas, e todos os campos de post.data ficam protegidos por tipos.
Como consultar dados de Content Collections e qual é a diferença entre getCollection e getEntry?
• getCollection('blog') busca todo o conteúdo da coleção e retorna um array
• getEntry('blog', 'my-post') busca um único item pelo slug e retorna um objeto, sendo mais eficiente para páginas de detalhes
Importe em um arquivo Astro:
import { getCollection, getEntry } from 'astro:content'
Uso dos dados:
• post.data contém os dados do frontmatter com tipagem completa do TypeScript
• O editor sugere automaticamente title, description, pubDate e outros campos
Filtragem de rascunhos:
const publishedPosts = allPosts.filter(post => !post.data.draft)
Exemplo de consulta individual:
const post = await getEntry('blog', slug)
if (!post) return Astro.redirect('/404')
const { Content } = await post.render()
Quais são os erros mais comuns em Content Collections e como corrigi-los?
1) MarkdownContentSchemaValidationError, quando o frontmatter não corresponde ao Schema:
• Verifique campos ausentes e adicione-os ou use .optional()
• Corrija nomes digitados incorretamente e padronize-os com o preenchimento automático do editor
• Confira o formato dos valores quando houver incompatibilidade de tipos
2) InvalidContentEntryFrontmatterError, quando há erro de sintaxe YAML:
• Verifique aspas, dois-pontos e recuo
• Use uma extensão de editor que valide a sintaxe YAML
3) Problemas com datas:
• Use z.coerce.date() em vez de z.date(); datas no YAML são escritas como strings, e z.coerce.date() faz a conversão automática
4) Tratamento de dados legados:
• Use .passthrough() para permitir temporariamente campos adicionais não definidos, mas apenas como solução provisória
• No longo prazo, padronize a estrutura do frontmatter
Checklist:
• O diretório content/ existe
• content.config.ts está no local correto, fora de content/
• As chaves de collections correspondem aos nomes dos diretórios
• A sintaxe YAML está correta
• Todos os campos obrigatórios estão preenchidos
• Os tipos dos campos correspondem ao Schema
Como organizar várias coleções e quais são as boas práticas de Schema?
• Se o site reúne blog, documentação e estudos de caso, crie coleções diferentes em src/content/blog/, docs/ e case-studies/
• Em content.config.ts, defina cada uma separadamente:
const blogCollection = defineCollection({...})
const docsCollection = defineCollection({...})
• Exporte o objeto collections:
'blog': blogCollection,
'docs': docsCollection,
'case-studies': caseStudiesCollection
• Cada coleção pode ter seu próprio Schema sem interferir nas demais
Boas práticas de design de Schema:
1) Mantenha poucos campos obrigatórios: exija apenas o necessário e use .optional() ou .default() nos demais
2) Use z.coerce.date() para datas e evite conversões manuais
3) Use camelCase nos nomes dos campos; pubDate combina melhor com as convenções do JavaScript do que pub_date
4) Divida objetos complexos; se o frontmatter ficar complicado, considere criar várias coleções ligadas por z.reference()
5) Escreva comentários claros no Schema para explicar à equipe a finalidade de cada campo
14 min de leitura · Publicado em: 24 nov 2025 · Atualizado em: 4 set 2026
Guia Astro
Se você chegou pela busca, o caminho mais rápido é ir para o post anterior ou próximo desta série.
Anterior
Como criar um blog com Astro do zero: guia completo da página inicial à implantação em 1 hora
Aprenda passo a passo a criar um blog pessoal com Astro, desde a preparação do ambiente até a implantação. Inclui página inicial, lista de artigos, categorias por tags, feed RSS e otimização de SEO. Um guia amigável para iniciantes montarem um blog pronto para produção em até 1 hora.
Parte 2 de 15
Próximo
Astro Markdown e MDX avançados: 7 técnicas para um blog mais profissional
Aprenda recursos avançados de Markdown e MDX no Astro: temas do Shiki, componentes personalizados, fórmulas com KaTeX, diagramas Mermaid e destaque de linhas de código.
Parte 4 de 15



Comentários
Entre com GitHub para comentar