Connecting relational data from Airtable using Gridsome and GraphQL queries

I’m trying to link related data in my Gridsome project that uses Airtable for the data source. I have a Furniture table and a Designers table in my Airtable setup. Each furniture record includes a “designers” field, which holds the designer’s ID who created that piece. My goal is to use this ID to fetch the designer’s complete information from the Designers table and create a relational query.

Here’s my gridsome.config.js:

module.exports = {
  siteName: 'Furniture Store',
  plugins: [
    {
      use: '@gridsome/source-airtable',
      options: {
        apiKey: 'keyhMlUJl9q3uzk0b',
        baseId: 'appkEp5El5UHrgnks',
        tableName: 'Furniture',
        typeName: 'Product',
      }
    },
    {
      use: '@gridsome/source-airtable',
      options: {
        apiKey: 'keyhMlUJl9q3uzk0b',
        baseId: 'appkEp5El5UHrgnks',
        tableName: 'Designers',
        typeName: 'Designers',
      }
    },
  ],
  templates: {
    Designers: '/designer/:id'
  }
}

My main page (Index.vue):

<template>
  <Layout>
    <h1>Furniture Store</h1>
    <ProductCard
      v-for="product in $page.allProduct.edges"
      :key="product.node.id"
      :product="product"
    />
  </Layout>
</template>

<page-query>
query {
  allProduct {
    edges {
      node {
        id
        name
        designer
        description
        type
        inStock
        images {
          thumbnails {
            large {
              url
              width
              height
            }
          }
        }
      }
    }
  }
}
</page-query>

<script>
import ProductCard from '~/components/ProductCard';

export default {
  components: {
    ProductCard
  }
}
</script>

In my ProductCard.vue component:

<template>
    <v-app>
        <v-card class="mx-auto my-12" max-width="374">
            <v-img
            height="250"
            :src="product.node.images[0].thumbnails.large.url"
            ></v-img>
            <v-card-title>{{ product.node.name }}</v-card-title>
            <v-card-text>
                <v-row align="center" class="mx-0">
                    <v-rating
                    :value="4.5"
                    color="amber"
                    dense
                    half-increments
                    readonly
                    size="14"
                    ></v-rating>
                    <div class="grey--text ml-4">4.5 (413)</div>
                </v-row>
                <div class="my-4 subtitle-1 black--text">
                    {{ product.node.description }}
                </div>
                <g-link to="/">Link to Designer</g-link>
            </v-card-text>
            <v-divider class="mx-4"></v-divider>
            <v-card-title>Tonight's availability</v-card-title>
        </v-card>
    </v-app>
</template>

<script>
export default {
    name: 'ProductCard',
    props: {
        product: {
            type: Object,
            required: true,
        },
    },
}
</script>

And my Designer.vue template:

<template>
   <h1>{{ $page.designers.name }}</h1>
</template>

<page-query>
query Designer($id: ID!) {
  designers(id: $id) {
    name
    id
    bio
  }
}
</page-query>

Any guidance on how to properly set up this relationship to access the designer details through the designer ID from the furniture table would be greatly appreciated!

theres another way - use the @refers directive in your schema. add this to gridsome.server.js: api.loadSource(actions => { actions.addSchemaResolvers({ Product: { designer: { type: 'Designers', resolve: (obj, args, { graphql }) => graphql.getNodeById('Designers', obj.designer) } } }) }) then you can query like designer { name bio } instead of just the designer field. way cleaner than manual lookups.

Your issue is that Gridsome’s Airtable plugin doesn’t auto-create GraphQL relationships between tables. You’ll need to set these up manually using gridsome.server.js. Create a gridsome.server.js file in your project root: javascript module.exports = function (api) { api.createPages(({ createPage, graphql }) => { // This runs after all data is loaded }); api.loadSource(({ addCollection, getCollection }) => { const products = getCollection('Product'); const designers = getCollection('Designers'); products.data().forEach(product => { if (product.designer) { const designerId = Array.isArray(product.designer) ? product.designer[0] : product.designer; product.designerDetails = designers.findNode({ id: designerId }); } }); }); }; Then update your page query to grab the designer details: graphql query { allProduct { edges { node { id name designer designerDetails { name bio id } description type inStock images { thumbnails { large { url width height } } } } } } } } This creates the relationship manually so you can access designer info directly in your components without extra queries.

Connecting relational data from Airtable with Gridsome and GraphQL can make product information easier to organize and manage, especially for furniture websites with many items and details. For businesses working with structured product data, these tools can help create smoother ways to display and update information online. For more information about furniture products and organized online collections, Learn more about the available options.

One thing I’d fix first: don’t keep the Airtable credential directly in gridsome.config.js.

Airtable retired the old API key authentication method, so you should be using a Personal Access Token now. I’d put that token in a .env file and reference it with process.env from the Gridsome config.

For the relationship, also keep in mind that an Airtable linked-record field normally gives you record IDs, and potentially more than one. So I’d treat designer as an array, resolve those IDs against the Designers collection in gridsome.server.js, and expose the resolved records as something like designerDetails.

Then your GraphQL query can be:

designerDetails { id name bio }

rather than doing another Airtable request from the Vue component.

To resolve linked Airtable records as relational data in Gridsome, you need to map the reference between collections in gridsome.server.js using addReference.

By default, @gridsome/source-airtable brings in linked record fields as raw arrays of record IDs. Without an explicit reference in the schema, GraphQL treats them as scalar strings instead of connecting them to the related collection.

In gridsome.server.js, hook into loadSource to link the designers field to the Designers collection:

module.exports = function (api) {
  api.loadSource(actions => {
    const products = actions.getCollection('Product')
    products.addReference('designers', 'Designers')
  })
}

Once that reference is defined, Gridsome resolves the designer IDs to their corresponding Designer nodes. You can then query the full nested designer details directly in your GraphQL page-query:

query {
  allProduct {
    edges {
      node {
        id
        name
        designers {
          id
          name
        }
      }
    }
  }
}

Make sure the field name in addReference matches the property name generated on the Product node, and restart the Gridsome develop server so the schema rebuilds.