Homepage Content Collection Implementation
Following our best practices audit, Priority 2 was implementing content collections for the homepage. This guide documents the migration from hardcoded content to a YAML-based content collection.
Why Content Collections for Homepage?
Moving homepage content to content collections provides:
- Non-developer editing - Content lives in YAML files instead of Astro components
- Type safety - Zod schemas validate all content at build time
- Version control - Track content changes separately from code changes
- Consistency - Single source of truth for all homepage content
- Flexibility - Easy to add new sections or modify existing ones
Implementation Steps
Step 1: Create Homepage Collection Schema
We added a comprehensive schema to content.config.ts
:
const homepage = defineCollection({
loader: glob({ base: "./src/content/homepage", pattern: "**/*.yaml" }),
schema: z.object({
hero: z.object({
title: z.string(),
description: z.string(),
buttons: z.array(z.object({
text: z.string(),
href: z.string(),
variant: z.enum(["primary", "secondary"]),
})),
}),
currentProjects: z.object({
title: z.string(),
projects: z.array(z.object({
title: z.string(),
description: z.string(),
url: z.string(),
})),
}),
contact: z.object({
title: z.string(),
email: z.string().email(),
}),
showcase: z.object({
title: z.string(),
sections: z.array(z.object({
title: z.string(),
type: z.enum(["projects", "writing", "compact"]),
items: z.array(z.object({
title: z.string(),
description: z.string().optional(),
excerpt: z.string().optional(),
date: z.string().optional(),
url: z.string(),
})),
})),
}),
posts: z.object({
title: z.string(),
maxPosts: z.number(),
}),
}),
});
Step 2: Create YAML Content File
Created /src/content/homepage/index.yaml
:
hero:
title: "Nathan Lane"
description: "Economist and Data Scientist exploring the intersection of technology, markets, and economic systems."
buttons:
- text: "Read Blog"
href: "/posts/"
variant: "primary"
- text: "View Research"
href: "/research/"
variant: "secondary"
currentProjects:
title: "Current Projects"
projects:
- title: "Economic Policy Research"
description: "Analyzing the impact of trade policies on regional economic development and labor markets."
url: "/research/trade-policy"
#... more projects
contact:
title: "Get In Touch"
email: "drnathanlane@gmail.com"
showcase:
title: "New Components"
sections:
- title: "Projects Grid"
type: "projects"
items:
- title: "SectionGrid.astro"
description: "Flexible grid container with responsive columns"
url: "#section-grid"
#... more sections
posts:
title: "Posts"
maxPosts: 10
Step 3: Update index.astro
Modified the homepage to use content collection data:
// Get homepage content from content collection
const homepageContent = await getEntry("homepage", "index");
const { hero, currentProjects, contact, showcase, posts: postsConfig } = homepageContent.data;---<!--Use content in template-->
<h1 class="heading-2 text-center">
{hero.title}
</h1>
<p class="text-body mt-4 mb-4">
{hero.description}
<!--Dynamic button rendering-->
<div class="flex justify-center gap-3 mt-6">
{hero.buttons.map((button) => (
<a
href={button.href}
class={button.variant === "primary"
? "inline-flex items-center px-3 py-1.5 text-xs font-medium text-bgColor bg-accent-base rounded hover:opacity-90 transition-all"
: "inline-flex items-center px-3 py-1.5 text-xs font-medium text-accent-base bg-color-100 hover:bg-color-150 rounded transition-colors"
}
>
{button.text}
</a>
))}
</div>
Key Benefits Realized
1. Content Editing Workflow
Non-developers can now edit homepage content by:
- Opening
/src/content/homepage/index.yaml
- Modifying text, links, or structure
- Committing changes via Git or web interface
- Automatic validation ensures content integrity
2. Type Safety Throughout
The Zod schema provides:
- Build-time validation of all content
- TypeScript types for all content access
- Clear documentation of content structure
- Prevention of missing or malformed data
3. Flexible Content Structure
The schema supports:
- Multiple showcase section types (projects, writing, compact)
- Optional fields where appropriate
- Extensible structure for future needs
- Consistent data shapes across sections
Migration Patterns
For other static pages, follow this pattern:
- Define content schema in
content.config.ts
- Create YAML/JSON file in appropriate content directory
- Import with getEntry() in your Astro component
- Replace hardcoded values with content collection data
- Test build to ensure schema validation passes
Next Steps
With homepage content collections complete, the remaining priorities are:
- Priority 3: Add font preloading to BaseHead.astro
- Priority 4: Add TypeScript prop interfaces to components
This implementation demonstrates how content collections can transform static content management while maintaining type safety and developer experience.