Module 04
Page 03
2 min

Extending References

Implementing references into our blog post


Now that we've made references for our Dog document and learned about Image asset references, let's finish talking about references by adding them to our Blog Post.

We'll be consolidating a lot of our Blog Post into various other document references, making it easier for you in the long run.

Creating an Author Document

First, we'll create an Author document - that way, we can reference data about you as a Blog Author, or if you have guest authors in the future that might write content for your hypothetical blog.

Create a new file /schemas/author.js with the following:

/schemas/author.js
export default {  name: 'author',  title: 'Author',  type: 'document',  fields: [    {      name: 'name',      title: 'Name',      type: 'string',      validation: (Rule) => Rule.required(),    },    {      name: 'slug',      title: 'Slug',      type: 'slug',      options: {        source: 'name',        maxLength: 96,      },    },    {      name: 'image',      title: 'Image',      type: 'image',      options: {        hotspot: true,      },    },    {      name: 'bio',      title: 'Bio',      type: 'text',      rows: 5,    },    {      name: 'socialMedia',      title: 'Social Media',      type: 'array',      of: [        {          type: 'labeledLink',        },      ],    },  ],}

Now, let's add it to /schemas/index.js:

/schemas/index.js
import blogPost from './blogPost'import labeledLink from './objects/labeledLink'// import dog from './dog'// import petInfo from './objects/petInfo'// import breed from './breed'import author from './author'
export const schemaTypes = [blogPost, labeledLink, author]
I commented out the Pet stuff since we won't really touch it anymore. Feel free to keep it if you'd like!

Now, let's make some big changes to our Blog Post document:

/schemas/blogPost.js
fields: [  {    name: 'title',    type: 'string',    title: 'Title',    group: 'content',    validation: (Rule) => Rule.required().max(50).min(10),  },  {    name: 'description',    type: 'text',    title: 'Description',    group: 'content',    rows: 3,    validation: (Rule) => Rule.required().max(100).min(10),  },  {    name: 'slug',    type: 'slug',    title: 'Slug',    group: 'metadata',    validation: (Rule) => Rule.required(),    options: {      source: 'title',      maxLength: 96,    },  },  {    name: 'content',    type: 'array',    title: 'Content',    group: 'content',    of: [      {        type: 'block',      },      {        type: 'image',      },    ],  },  {    name: 'authors',    type: 'array',    title: 'Authors',    group: 'metadata',    of: [      {        type: 'reference',        to: {type: 'author'},      },    ],  },  {    name: 'coverImage',    type: 'image',    title: 'Cover Image',    group: 'content',    options: {      hotspot: true,    },    fields: [      {        name: 'description',        type: 'string',        title: 'Description',      },    ],  },],

I removed a bunch of fields that we won't be using - these are the fields we'll be using from now on, but feel free to keep the old ones or make your own!

Everything here should look pretty familiar - except the new authors field. This is an array of references to authors. This way, you can have several different authors on a blog post:

With this new reference array, we can create authors directly in this side view. You might also notice we have a slug for the author - this is in-case we want to make pages that contain author information.

Querying a Blog Post with GROQ

Ok, so now that we have our blog post document complete, how would we get the data with GROQ? What data do we need? The best part about GROQ is that we can choose what we want, and leave behind what we don't want.

Let's try this query:

*[_type == "blogPost"][0] {  title,  description,  "slug": slug.current,  coverImage,  content,  authors[]->{    name,    image,    socialMedia[] {      label,      url    }  }}

You can see when we have arrays and want certain fields, we use []. For references, we use ->. And to get inner fields, we use ..

Now, let's fetch our data:

{…} 6 properties  authors:[…] 1 item    0:{…} 3 properties      image:null      name:Greg Heffley      socialMedia:[…] 2 items        0:{…} 2 properties          label:Twitter          url:https://twitter.com        1:{…} 2 properties          label:Instagram          url:https://instagram.com  content:[…] 4 items  coverImage:{…} 3 properties  description:And this is my first blog post's description. Kinda great, huh?  slug:this-is-my-first-blog-post-can-t-you-believe-it  title:This is my first blog post! Can't you believe it??
I left the coverImage and content fields closed, the data should load in!

This is practically all of the data we'll need when making our blog post!

Ritesh Kanchi © 2025