How to Organize Your Site Content with Astro Collections
Managing content for your website, like blog posts or product details, can become tricky as your site grows. Astro’s content collections offer a structured way to handle this data. You can store content locally using files like JSON or Markdown, or fetch it from external sources. This guide will show you how to use local JSON files to create and manage your site’s content with Astro’s powerful content collections feature.
What You’ll Learn
This tutorial will guide you through setting up Astro content collections using local JSON files. You will learn how to:
- Store your data in a structured JSON file.
- Define a content collection in Astro using a configuration file.
- Implement data loading and define a data schema for type safety.
- Load and display your collection data on a web page.
- Update components to work with the structured collection data.
Prerequisites
- Basic understanding of web development concepts.
- An existing Astro project set up.
- Familiarity with JavaScript and JSON.
Step 1: Add Your Data to the Project
First, you need to place your data within your Astro project. A common practice is to create a content folder inside the src directory. This keeps your content organized and separate from your code.
Inside the content folder, create a JSON file, for example, books.json. This file will hold your data as a list of objects. Each object represents an item, like a book, and should have a unique id, along with other properties such as title, author, rating, and summary.
Example src/content/books.json:
[
{
"id": "book-1",
"title": "The Hitchhiker's Guide to the Galaxy",
"author": "Douglas Adams",
"rating": 5,
"summary": "A comedic science fiction series about the last surviving human."
},
{
"id": "book-2",
"title": "Pride and Prejudice",
"author": "Jane Austen",
"rating": 4,
"summary": "A classic novel of manners, love, and social standing."
}
]
It’s crucial that each item in the JSON array has a unique id. This ID is used by Astro to identify each piece of content within the collection.
Step 2: Define Your Content Collection
Next, you need to tell Astro about your new content collection. Create a file named content.config.ts directly inside your src folder. This file is where you’ll define all your content collections.
Inside content.config.ts, you’ll start by importing a necessary function. You need to import defineCollection from Astro’s content module. This function helps Astro understand how to manage your data.
import { defineCollection } from 'astro:content';
Now, use the defineCollection function to set up your books collection. You’ll create a constant, perhaps named books, and assign the result of calling defineCollection to it.
const booksCollection = defineCollection({
// Configuration goes here
});
Step 3: Configure the Data Loader
Within the configuration object for defineCollection, you need to specify how Astro should load the data. This is done using a loader property.
Astro provides built-in loader functions. For a single file like our books.json, you’ll use the file loader. Import this loader from astro/loaders.
import { defineCollection, file } from 'astro:content';
Then, set the loader property in your collection definition. The value should be the file loader, pointing to your JSON data file. The path is relative to your project’s root directory.
const booksCollection = defineCollection({
loader: file('../content/books.json'), // Path relative to content.config.ts
// Schema will go here
});
Expert Tip: If you had multiple JSON files in a folder, you could use the glob loader instead of file to load them all at once. For example: glob('../content/books/*.json').
Step 4: Define the Data Schema
To ensure your data is consistent and to get helpful code suggestions (IntelliSense), you should define a schema for your collection. Astro uses Zod for schema definition, which needs to be imported from astro/zod.
import { defineCollection, file } from 'astro:content';
import { z } from 'astro/zod';
Add a schema property to your collection configuration. This property will use Zod to describe the shape of your data objects. For our books, we’ll define fields for id, title, author, rating, and summary.
const booksCollection = defineCollection({
loader: file('../content/books.json'),
schema: z.object({
id: z.string(),
title: z.string(),
author: z.string(),
rating: z.number(),
summary: z.string(),
}),
});
Using z.string() and z.number() tells Astro that these fields must be strings and numbers, respectively. This helps prevent errors and makes your code easier to work with.
Step 5: Export Your Collections
Finally, you need to export your defined collection so Astro can use it. At the bottom of your content.config.ts file, export an object named collections. This object should contain all the collections you’ve defined.
export const collections = {
books: booksCollection,
};
After saving content.config.ts, it’s a good practice to restart your Astro development server. This ensures that Astro recognizes the new configuration and any potential type errors in your templates are resolved.
Warning: If you don’t restart the dev server after changing the config, you might see type errors that aren’t actually present in your code.
Step 6: Load and Display Data on Your Page
Now you can use your new content collection in your pages. Open the page where you want to display the book data, for instance, src/pages/books.astro.
Remove any existing hardcoded data array for books. Instead, use Astro’s getCollection function to fetch data from your defined collection. Import getCollection from astro:content.
import { getCollection } from 'astro:content';
// Remove old data definition
// const books = [...];
const books = await getCollection('books');
The getCollection('books') function retrieves all items from your ‘books’ collection. Astro processes the data at build time, making it available to your component.
Step 7: Update Your Components
When you use getCollection, the data objects you receive have a slightly different structure than plain JavaScript objects. Each item is a CollectionEntry, and its actual data (like title and author) is nested inside a data property.
If you have a component, like a BookCard, that receives book data as a prop, you’ll need to update its type definition. Import CollectionEntry from astro:content and specify the collection name ('books') in angle brackets.
// In your BookCard component (or wherever props are defined)
import type { CollectionEntry } from 'astro:content';
interface Props {
book: CollectionEntry;
}
const { book } = Astro.props;
Then, when accessing properties within your component’s template, you’ll need to reference the data property. For example, instead of book.title, you’ll use book.data.title.
Title: {book.data.title}
Author: {book.data.author}
Rating: {book.data.rating} / 10
{book.data.summary}
Tip: This change ensures your component correctly understands the structure of data coming from Astro’s content collections, enabling IntelliSense and type checking.
Step 8: Add Remaining Data Fields
Now, let’s add the remaining fields like rating and summary to your page. You can display them within your component’s template just like the title and author.
For instance, you might want to show the rating prominently and the summary below it. You can also add a link for future details pages.
{book.data.summary}Read Review
You can also add some basic styling for the summary if needed.
.book-summary {
font-size: 1em;
}
Remember to remove any old interface definitions for your book data within the component itself, as the type is now handled by CollectionEntry.
Conclusion
By following these steps, you’ve successfully set up and used Astro’s content collections with local JSON data. This method provides a robust way to manage your website’s content, offering better organization, type safety, and a smoother development experience. You can now easily load and display your book reviews, and you’re well-prepared to explore other data sources or file types in the future.
Source: Astro Crash Course #8 – Content Collections (with JSON) (YouTube)