Astro Crash Course #8 - Content Collections (with JSON)

Net Ninja| 00:10:34|Apr 9, 2026
Chapters10
Overview of how content collections help manage and query data for a site, with local JSON data as the initial example.

Net Ninja’s Astro crash course shows how to set up content collections with JSON data, including loaders, schemas, and build-time data loading for a books page.

Summary

Net Ninja breaks down content collections in Astro by using a local JSON data source (books.json) to power a books page. We learn to organize content under a content folder, or keep it alongside source files, with a convention that helps keep data tidy. The instructor demonstrates defining a collection in content.config.ts using defineCollection from astro/content, configuring a loader (file) and a schema (via zod) to enforce structure like id, title, author, rating, and summary. The video then covers exporting the collections object and restarting the dev server to clear type errors. On the page, getCollection is used to pull data at build time, replacing a manually defined books array, and the card component is adjusted to accommodate Astro’s collection entry type (data stored under a data field). Finally, Axios-style realism is added by displaying rating and summary on the card and prepping the Read Review link for later navigation. If you’re following along, you’ll end with a type-safe, build-time loaded content collection that powers the books page using JSON data.

Key Takeaways

  • Define an Astro content collection with defineCollection from 'astro/content' and export it via a collections object.
  • Use the file loader to read a single JSON file (books.json) from source/content and wire it to the collection.
  • Enforce data shape with a zod schema (id: string, title: string, author: string, rating: number, summary: string) for type safety and IntelliSense.
  • Load collection data at build time with getCollection('books') and map it into a page component, replacing a hard-coded array.
  • Adjust components to handle Astro collection entry objects by accessing properties via the data field (collection entry).
  • Restart the dev server after adding or changing content collections to clear type errors and see updates.
  • Extend the UI to display new fields like rating and summary and prep for navigation with a Read Review link.

Who Is This For?

Frontend developers using Astro who want to organize site content as structured, build-time data using content collections with JSON (and later Markdown). Great for blogs, reviews, or any content-heavy pages.

Notable Quotes

"And by using Astro's content collections, we're able to then easily query and load data into components."
Intro to why content collections matter and how they connect data to UI.
"The first thing I'm going to do in this file is import a function that we need by saying import then curly braces and the function name is define collection... coming from astro"
Shows how to define a new content collection.
"This field is optional, but by creating the schema, we're going to ensure type safety and intellisense."
Explains the purpose of the schema with zod.
"We can now use getCollection to fetch the books collection and Astro will load the data at build time."
Demonstrates loading data into the page using the collection.
"When you use a collection entry, all the properties are stored on a data field, so you access book.data.title and so on."
Clarifies how to adapt to collection entry structure in the UI.

Questions This Video Answers

  • How do you set up a content collection in Astro with JSON data?
  • What is the difference between a content collection and a regular data array in Astro?
  • How can I enforce data shape in Astro collections using Zod?
  • How do I load content collections at build time with getCollection in Astro?
  • What changes are needed in a React-style card component when using Astro content collections?
AstroContent CollectionsJSON dataType safetyZodgetCollectioncollection entrybuild-time data loadingcards componentloader: file
Full Transcript
All right, then. So, now we've got some books data showing on the page. I want to introduce something called content collections. And content collections are something Astro uses to help us manage and query data for your site like blog posts or page content or in our case, book reviews. And we can either add this data locally to the project, for example, using JSON or markdown files for the content. Or we could fetch it from a remote source like a database or an API endpoint. And by using Astro's content collections, we're able to then easily query and load data into components. And we can also add scheas for collections, which then enforce type safety and add IntelliSense for when we're using the data in the templates. In this series, we're going to stick with local data and buildtime collections, which is where the data gets loaded from your project and rendered at build time. But if you want me to make a tutorial about using remote data and live content collections which are loaded on demand by the server when a request comes in, please let me know down in the comments. Anyway, in this lesson, we're going to start by using JSON to store books data in and then we'll make a content collection for that books data and then we'll try loading it in the books page. In the next lesson, we'll switch to using markdown files instead. So this way you're going to get an idea of how to use content collections with those as well. So then the first thing we need to do is add the JSON data to the project which I've already done. You can see it right here in a folder I made called contents which is in the source directory. Now you don't have to put your content in a content folder. You can add it directly to the source folder if you wanted to but this is a common convention and it also keeps your content more organized. So the file is called books.json JSON. And inside that, we've got some JSON already created, which is just a list of books like we've already seen where each one's got a title, an author, and now also a rating, and a short summary because I also want to show both of those things on the books page as well where we list them out. I also added a unique ID to each one because when we're using a JSON file as the data source for a content collection, each one, each object needs an ID to identify it. Anyway, the next thing we need to do is define this collection within our application. And we do that by making a file directly in the source folder called content.config.ts. And it's inside this file that we define all of our content collections because we can have more than a single one if we wanted to. So the first thing I'm going to do in this file is import a function that we need by saying import then curly braces and the function name is define collection and that comes from astro then a colon and then the content module. So next we can come down here and we can use that function to define a new collection. And we do that by first of all making a new constant which I'm going to call books because that's going to be the name I'm giving to the collection. And then we set that equal to the define collection function and we invoke it. Now inside this we need to pass an object as an argument where we can now configure the collection. So there's two properties we should add inside here. a loader property which should be a function to load the data source and a schema property which defines how the data should look and we do that using zod. So then let's start with the loader property. I'm going to add that property down here then and the value of that should be a loader function which loads the data in. Now Astro comes with a couple of loader functions baked into it that we can use. one called file which loads data from a single file and one called glob which loads data from multiple files using a glob pattern to find and return those files. In our case, we just need to load data from a single file for now. So, we're going to be using the file function and we need to make sure that that gets imported from astro/loaders as well. So then now we need to supply the path to this data file relative to the root of the project. In our case, that's going to be the source folder first, then the content folder, then the file itself, which is books.json. Okay, so now we've got the loader. The next thing we want to add is the schema for this collection by adding a schema property. And this field is optional, but by creating the schema, we're going to ensure type safety and intellisense. So I think it is worth doing in my opinion. So we use zod to define these schemas in Astro. And we need to import that up here first by saying import then curly braces then zed and that comes from astro slash zod. Then back down here we can give a value to this schema property which is zed.object and we invoke that function and we pass through an object as an argument. So this object will represent how the object should be structured with what properties and type should be on it. In our case then we should have the ID property right and the value of that should be a string. So we can say zstring to mark that as such and also invoke this because it's a function. Then we've got a title property on each book which is also a string. So we can say z.string again for that and invoke it. Then we've got the author property which again is going to be zed dot string. Uh after that we have a rating property and this time it's a number. So we can say zed dot number this time and invoke it. And finally we've got the summary property which again is a string. So we can say z.string for that as well. All right. And that is it. We have now defined a collection which includes a loader to load the data and a schema to define its structure. Next then we need to export this collection by saying down here at the bottom of the file export const collections and then we set that equal to an object. And for each collection we define in this file we just add it to this exported object as a property. In our case at the moment it's just a books collection. So I'm going to add that in. All right. So now we can save this file. And at this point, it's probably a good idea to restart the dev server. Otherwise, you might still see some type errors in the templates when you use this collection. But once you've restarted the server, those errors and warnings normally go away. All right. So once you've done that, we can start using the content collection in the books page. So I'm going to open up that file and where we currently define the books array. I'm going to delete all of that and instead we're going to say const books is equal to await and then we can use another built-in function to get a collection of data which is called get collection. And we also need to make sure that this gets imported from the Astro content module. So we invoke this function and we pass in the name of the collection that we want to get which in our case is just books. And now at build time Astro uses this books collection that we define to load the data and then bring it into this component. And this books constant will then be an array of book object entries much like before. So we're still mapping through the array the same as before, but now we see an error where we pass the book into the card component as a prop. And the reason we get that error is because now we're passing through a slightly different kind of object than before. And if we take a look at the card component that we made, we're saying the book prop should look like this with a title and author properties which are both strings. But in actual fact, we're passing through a book object which has a special collection entry type defined by the schema we made for the collection. So we need to update this book property in the props interface to reflect that. So let's delete all of this for now and then we'll replace it with a type called collection entry which we need to import from the Astro content module and inside angle brackets after this type we need to declare which content collection the schema is defined in which in our case is books. So, if we save this file and then head back to the books page, we should see now that the error has gone because the props interface now matches what we're passing in a collection entry. Now though, we've got some errors in the card component where we output the different properties. And again, that's because the way a collection entry object is structured is slightly different to how we structured the book objects before. So when we use a collection entry object, all of the properties are stored on a data field. And all we have to do is add that in before the title and before the author. And then the errors should go away. All right. So finally, I just want to add in the other two fields from the data, the rating and the summary. And then we'll preview this in a browser to make sure it all works. Okay. So I'm going to do the rating, I think, at the top. So let's come up here and I'll say P. And I'll give this a class of in fact no what we'll do is we'll put the rating next to it. Next to the title we'll do the book rating. So book data rating and then after this I'm going to do a slash and then 10. So it's whatever the rating is out of 10. So eight out of 10 for example. Then at the bottom we'll do the book summary. So b uh p and then a class of book hyphen summary like so. And then we'll output the book summary by saying book data dots summary. And notice we get that intellisense as well, which is good. All right, cool. And then also I'm going to do an anchor tag down here. We'll leave the hf blank for now. And then we'll say read review because later we're going to be able to click on this to go to the book details page which we've not created yet. I'm just kind of prepping this for later. That's all. All right. Then finally, I'm going to come down here and just add one class for the book summary we just added. So book hyphen summary and then inside here we'll just say font size is 1 m. All right then. So I can save that now and let's preview this in a browser to make sure everything works. And in fact before we do that we can get rid of this interface right here this book because we're no longer defining the books inside this component. So let's get rid of that as well. Then we'll save and preview. Okay cool. So now that all works, we can see everything on the page.

Get daily recaps from
Net Ninja

AI-powered summaries delivered to your inbox. Save hours every week while staying fully informed.