Build a site with Nextjs and Airtable
Tags: react, beginners, webdev, nextjs
Published: 2020-10-19 07:29:55

I'm going to show you how to build websites and apps, using Nextjs and Airtable as a CMS/API/Database.

## Project
We will be building a Seth Godin style blog, see [here](https://seths.blog/). The short posts are displayed on the home page. A note style blog. If you don't want to make a blog, pick other data you want to display. Displaying data from our Airtable is the important part.

### Why Airtable?
[Airtable](airtable.com) is a spreadsheet app, with extra bits. It's easy to setup and perfect for creating your own little side projects. Create your own API without having to learn backend. Airtable has a mobile app, which means you can update your database on the go.

### Why Nextjs?
Nextjs allows you to write React as normal. But with the option of static sites for improved speed and SEO improvements. We will be using nextjs's static site feature to create our site at build time. If you are new to nextjs, don't worry. It's easy to do this, and the syntax will look familiar to you.

## Setup Airtable CMS
We need data first. Let's create a database for adding our posts. 

Go to [airtable.com](airtable.com) and create a 'base'.

![Airtable screen](https://dev-to-uploads.s3.amazonaws.com/i/r7uer2izp3ivrp7e5x05.png)

In your base rename the table and fields. I prefer to name things in lowercase to avoid and trouble further on.

![Airtable screenshot](https://dev-to-uploads.s3.amazonaws.com/i/dmzgk1tyskg15qm0ujwf.png)

Make sure you enable rich text formatting. This allows you to add lists, headers and other text formatting options.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/b8yrva24ae9ycp46ow4t.png)

Let's add dummy data for three fake posts.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/200670q9x2zsv9u1s2g0.png)

See I have added a header, list and a word in bold, in my dummy posts. This is for working on formatting in our app. We will be converting the markdown to html.

## Nextjs
In a terminal use the command `npx create-next-app your-project-name-here`. This will give us nextjs's boiler plate. If you've used `create-react-app` this will be familiar. You get a good starting point.

Open it up in your text editor. I'm using VScode. Theres an `index.js` file in the `pages` folder. This is our main for displaying.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/4xqainlyefewzxqlgdp3.png)

Open a terminal. Top tip: If you're in VScode, use the command `ctrl ~` to open or close the in house terminal. The command `npm run dev` will start our nextjs app in a server.

You should see the below on `localhost:3000`

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/oh308fm5r72uk1mv3bpl.png)

If you see this, you're good to go. Before doing anything, clean up your code. Delete the api folder along with, style.modules. And clean up the index.js code. Mine looks like this:

```jsx
import Head from 'next/head';

export default function Home() {
  return (
    <div>
      <Head>
        <title>Godin style blog demo</title>
        <link rel='icon' href='/favicon.ico' />
      </Head>
      <main>
        <h1>Godin style blog demo</h1>
      </main>
    </div>
  );
}

```

## Airtable API
We need to connect our base to our nextjs app. Go to [airtable.com/api](airtable.com/api)

You will be treated with this page:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/lq2qyoborf7gkauqu9hl.png)

Go into the base you're using. In there you will find Airtables, fantastic docs.

The part we are interested is on the *JavaScript* tab, under *authentication*.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/rsqot6a9qd9ftcjcl3uo.png)

Don't worry if this looks alien to you. We will be using, airtables npm package to complete our requests. Go ahead and `npm install airtable`.

### Hiding secrets

In our code create a `.env` file at the top of directory. This is where we hide our environment variables in nextjs.

In `.env` add your secrets.

```
AIRTABLE_API_KEY=YOUR_KEY_HERE
AIRTABLE_BASE_ID=YOUR_BASE_ID_HERE
AIRTABLE_TABLE_NAME=YOUR_TABLE_HERE
```

When you have added your secrets, make sure `.env` is added to `.gitignore`. You don't wan to share these on Github.

**Important** - restart your server for nextjs to pick up your environment variables. 

## Getting our data
We will create a file for fetching our data. Create a `lib` folder and within that a `getPosts.js` file. This is where our airtable code will go, for handling data fetching.

In `getPosts.js` add the following code. The code connects to airtable and fetches the records form the base you have provided.

```javascript
const Airtable = require('airtable');

const base = new Airtable({
  apiKey: process.env.AIRTABLE_API_KEY,
}).base(process.env.AIRTABLE_BASE_ID);

const table = base(process.env.AIRTABLE_TABLE_NAME);

export default async function getPosts() {
  const records = await table.select({}).all();

  console.log(records);

  return records;
}
```

To see if this works, call the `getPosts()` function in `index.js`. In your **terminal** you will see a tonne of information. With this data bombardment, you will see `fields`. This is the data we need to display.

In `getPosts()` we will create two functions for minifying the data and giving us what we need.

```javascript
const Airtable = require('airtable');

const base = new Airtable({
  apiKey: process.env.AIRTABLE_API_KEY,
}).base(process.env.AIRTABLE_BASE_ID);

const table = base(process.env.AIRTABLE_TABLE_NAME);

// maps over the records, calling minifyRecord, giving us required data
const getMinifiedRecords = records => {
  return records.map(record => minifyRecord(record));
};

// gets the data we want and puts it into variables
const minifyRecord = record => {
  return {
    id: record.id,
    fields: record.fields,
  };
};

export default async function getPosts() {
  const records = await table.select({}).all();
  const minifiedRecords = await getMinifiedRecords(records);

  console.log(minifiedRecords);

  return minifiedRecords;
}
```

**Remember check in your terminal** for the `console.log`. As of writing this, my browser is giving an error, requesting an API key. 

## Displaying content

We have our content in the console, we need to display this. We will be using nextjs's `getStaticProps()` built in function for getting the content on build time.

We do this in `index.js` because that's our page being rendered.  We add out `getStaticProps()` function at the bottom of our file.

```javascript
export async function getStaticProps() {
  const posts = await getPosts();

  return {
    props: {
      posts,
    },
  };
}
```

To give the home function access to the data we pass it in as props.

```jsx
export default function Home({ posts }) {
```

To see the data displayed on the DOM, map over it as you would in any React app.

```jsx
import Head from 'next/head';
import getPosts from '../lib/getPosts';

export default function Home({ posts }) {
  return (
    <div>
      <Head>
        <title>Godin style blog demo</title>
        <link rel='icon' href='/favicon.ico' />
      </Head>
      <main>
        <h1>Godin style blog demo</h1>
        <ul>
          {posts.map(post => (
            <li key={post.id}>
              <h3>{post.fields.title}</h3>
              <time>{post.fields.published}</time>
              <div>{post.fields.content}</div>
            </li>
          ))}
        </ul>
      </main>
    </div>
  );
}

export async function getStaticProps() {
  const posts = await getPosts();

  return {
    props: {
      posts,
    },
  };
}
```

If all has gone to plan you should, your posts.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/uxwj0101u6qk3hwuj0zh.png)

One thing we need to add to `getStaticProps()`. Because this data is given to us on build time, means if we add a new post. It won't be added, until you rebuild the site. But nextjs gives us a way to fix this. Adding ` revalidate: 1` to our function, makes nextjs look for anything new added. If you add a new post. Nextjs will pick it up. The number added is how frequent you want nextjs to check. Your function should look like this.

```javascript
export async function getStaticProps() {
  const posts = await getPosts();

  return {
    props: {
      posts,
      revalidate: 1,
    },
  };
}
```

## Formatting our text
Our rich text from airtable is given to us as markdown. You will see this displayed on the DOM as '*','###'. We want this to be turned into html.

We will be using the package [marked](https://marked.js.org/) for this. Marked is easy to use. Install one package `‌npm install marked`. Next wrap the markdown content, we want to display in a `marked()` function.

Import our package in `index.js` `import marked from 'marked'`.

Before we displayed our content in a `<div>`. We will change that to display our content in HTML. Using `dangerouslySetInnerHTML` and wrapping our `post.fields.content`  in `marked()`.

```javascript 
<div
                dangerouslySetInnerHTML={{
                  __html: marked(post.fields.content),
                }}
              />
```

Once your index page looks like this

```jsx
import Head from 'next/head';
import marked from 'marked';
import getPosts from '../lib/getPosts';

export default function Home({ posts }) {
  return (
    <div>
      <Head>
        <title>Godin style blog demo</title>
        <link rel='icon' href='/favicon.ico' />
      </Head>
      <main>
        <h1>Godin style blog demo</h1>
        <ul>
          {posts.map(post => (
            <li key={post.id}>
              <h3>{post.fields.title}</h3>
              <time>{post.fields.published}</time>
              <div
                dangerouslySetInnerHTML={{
                  __html: marked(post.fields.content),
                }}
              />
            </li>
          ))}
        </ul>
      </main>
    </div>
  );
}

export async function getStaticProps() {
  const posts = await getPosts();

  return {
    props: {
      posts,
      revalidate: 1,
    },
  };
}
```

Have a look at your app. You should see that the markdown has been formatted and changed to HTML. Magic.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/yulwtux47ros2d2sef1w.png)

## Conclusion 

We have built a 'Seth Godin' style, thoughts blog. Made with nextjs and Airtable. Airtable is great for templating a database or using as a CMS. It's powerful. 

You can update your CMS any time with Airtable's mobile app. 

Nextjs is versatile, and is great for static sites due to its readable syntax. Unlike other frameworks that require graphQL knowledge. 

I wish I knew about using Airtable as an API months back. It would of helped with getting ideas out, without the bother of backends or proper databases.

## Where to go from here
* The app needs styling. I will continue, this app by writing an article on adding [TailwindCSS](https://tailwindcss.com/) for styling.
* We need to host this site. I will write an article on hosting on [Vercel](https://vercel.com/)
* Add dynamic routing with nextjs.
* SEO improvements

If your'e new to nextjs, it's worth looking at the docs. They're a rare example of decent documentation.

### Project ideas using airtable + nextjs
Theres many things you can make using airtable and nextjs. They're good for practise. A few to get you started: 
* Favourite quotes app
* [Nomad List](https://nomadlist.com/) style site
* One sentence a day journal 

## Let's connect
[Twitter](https://twitter.com/davidbell_space)