Build a Blog with Astro, microCMS, and Vercel

typescript dev.to

In this tutorial, we will build a simple blog using Astro, microCMS, and Vercel.

Astro is a modern web framework designed for fast, content-focused websites. It is especially well suited for blogs, documentation sites, landing pages, and corporate websites where most of the content can be rendered as static HTML.

microCMS is a headless CMS that lets you manage content through APIs. By combining Astro with microCMS, you can keep your frontend fast while allowing editors and content teams to manage blog posts from a user-friendly CMS dashboard.

Finally, we will deploy the blog to Vercel.

By the end of this guide, you will have a blog that:

  • Fetches blog posts from microCMS
  • Uses Astro Content Loader to manage external content
  • Displays a blog post list
  • Generates detail pages for each blog post
  • Deploys to Vercel

What is Astro?

Astro is a web framework for building fast websites.

One of Astro’s key ideas is to send as little JavaScript to the browser as possible. Instead of turning every page into a JavaScript-heavy application, Astro renders HTML on the server by default.

Astro is also known for its islands architecture. This allows you to keep most of the page static while adding interactivity only where it is needed. You can use UI frameworks such as React, Vue, Svelte, Preact, Solid, and others for interactive components.

Preparation

In this article, we will use the following versions. Some features may differ slightly depending on the version.

  • Astro 6.3.8
  • microcms-js-sdk 3.4.0

Create a New Astro Project

Now, let’s create an Astro project.

Open your terminal and run the following command.

npm create astro@latest
Enter fullscreen mode Exit fullscreen mode

Follow the prompts in your terminal.

Checking the Site in Your Local Environment

Now that the project is ready, let’s start the development server.

cd astro-microcms-blog
npm run dev
Enter fullscreen mode Exit fullscreen mode

Open http://localhost:4321/ in your browser, and you should see the Astro welcome page.

Preparing microCMS

Next, let’s prepare microCMS so that we can manage blog posts there.

Creating a microCMS Service

A service is the largest management unit in microCMS.

In principle, almost all microCMS concepts, such as APIs, media, permission management, plans, and billing information, are tied to a single service.

Let’s go through the steps to create a new service.

First, access the admin dashboard at https://app.microcms.io/. Click the + Add button in the upper-right corner of the screen. You will then see a screen where you can choose how to create a service.

There are two main ways to create a service.

  1. Create your own
  2. Template

This time, select Create your own.

Then, the service information input screen will appear. Enter astro-microcms-blog as the service name, and enter any value you like for the service ID.

Finally, click the Create service button.

Now the service has been created.

Setting Environment Variables

First, we will set environment variables to safely manage values such as the microCMS API key.

Create a new .env file in the root directory of your project and enter the following information.

MICROCMS_API_KEY=<YOUR_KEY_VALUE>
MICROCMS_SERVICE_DOMAIN=<YOUR_SERVICE_DOMAIN>
Enter fullscreen mode Exit fullscreen mode
  • MICROCMS_API_KEY: You can check this from Service Settings > API Key in the microCMS admin dashboard.
  • MICROCMS_SERVICE_DOMAIN: This is the service ID you created earlier. You can also check it from the microCMS admin dashboard URL. In https://xxxxxxxx.microcms.io, the xxxxxxxx part is your service domain.

Installing the microCMS JavaScript SDK

Next, install the microCMS JavaScript SDK to fetch data from microCMS.

npm install microcms-js-sdk
Enter fullscreen mode Exit fullscreen mode

Creating a Blog API in microCMS

Next, let’s prepare the blog API in the microCMS admin dashboard.

You may see an option called Blog, but ignore it for now and create the API from Create your own.

Enter the following values for API Name and Endpoint.

For the API type, select the list format.

Prepare the following fields for the API schema.

  • Title
  • Description
  • Hero Image
  • Body

Turn on the Required field switch for all fields.

After creating the API, create content from the + Add button.

The fields you defined earlier will be displayed, so enter some sample content.

Once you have finished entering the content, click the Publish button to publish it.

Let’s also add one more article.

Then, the list screen will look something like this.

Preparing the Content Loader

Astro has a feature called Content Collections, which allows you to manage local files such as Markdown as type-safe content.

To make external data compatible with Content Collections, you need to introduce a dedicated loader.

In this step, we will add a loader to read content managed in microCMS.

First, create src/content.config.ts and add the implementation of a Content Loader to read data from microCMS.

import { defineCollection } from 'astro:content';
import { z } from 'astro/zod';
import type { Loader } from 'astro/loaders';
import { createClient } from 'microcms-js-sdk';

function getClient() {
  return createClient({
    serviceDomain: import.meta.env.MICROCMS_SERVICE_DOMAIN,
    apiKey: import.meta.env.MICROCMS_API_KEY,
  });
}

const microCMSImageSchema = z.object({
  url: z.string(),
  width: z.number().optional(),
  height: z.number().optional(),
  alt: z.string().optional(),
});

const microCMSDateFields = {
  createdAt: z.string(),
  updatedAt: z.string(),
  publishedAt: z.string(),
  revisedAt: z.string(),
};

function microCMSLoader(endpoint: string): Loader {
  return {
    name: `microcms-${endpoint}`,
    load: async ({ store, parseData, logger }) => {
      try {
        logger.info(`Fetching ${endpoint} data from microCMS...`);
        const contents = await getClient().getAllContents({ endpoint });
        store.clear();

        for (const content of contents) {
          const { id, ...fields } = content;
          const data = await parseData({ id, data: fields });

          store.set({
            id,
            data,
            rendered: {
              html: data.body,
            },
          });
        }

        logger.info(`Fetched ${contents.length}${endpoint} items`);
      } catch (error) {
        const message = error instanceof Error ? error.message : String(error);
        logger.error(`Failed to fetch ${endpoint} from microCMS: ${message}`);
      }
    },
  };
}

const blog = defineCollection({
  loader: microCMSLoader('blog'),
  schema: z.object({
    title: z.string(),
    description: z.string(),
    heroImage: microCMSImageSchema,
    body: z.string(),
    ...microCMSDateFields,
  }),
});

export const collections = {
  blog,
};
Enter fullscreen mode Exit fullscreen mode

Now you are ready to call microCMS content in a type-safe way from anywhere.

Displaying the Article List

Now that the preparation is complete, let’s start writing the Astro source code.

This time, we will assume that the blog article list is displayed on the top page.

First, replace the contents of src/pages/index.astro with the following.

This file is called when you access the root path, http://localhost:4321/.

---
import Layout from '../layouts/Layout.astro';
import { getCollection } from "astro:content";

const posts = await getCollection("blog");
---

<Layout>
  <main>
    <ul>
      {posts.map((post) => (
        <li>
          <a href={post.id}>{post.data.title}</a>
        </li>
      ))}
    </ul>
  </main>
</Layout>
Enter fullscreen mode Exit fullscreen mode

The --- at the beginning is called a code fence.

Inside the code fence, you can write JavaScript logic.

By default, this part is executed on the server side at build time, and the JavaScript code does not remain in the built site.

In this section, we fetch the list of articles from microCMS and display them on the screen as list elements.

With this setup, the browser display will look like this.

We were able to display a list of articles fetched from microCMS.

Creating the Blog Article Detail Page

At this point, we have not created a detail page yet.

So, if you click a link, you should see a 404 page like the one below.

Let’s create a detail page so that it does not result in a 404.

Setting Up Routing

In Astro, files under src/pages basically correspond to website paths.

However, when the path value changes dynamically, as in this case, we need to set up dynamic routing.

Reference: https://docs.astro.build/en/guides/routing/

This time, create a file named src/pages/[postId].astro so that pages can be accessed with paths such as http://localhost:4321/post-id.

Write the following code.

---
import Layout from "../layouts/Layout.astro";
import { getCollection } from "astro:content";

// Get all paths for article detail pages
export async function getStaticPaths() {
 const posts = await getCollection("blog");
 return posts.map((post) => ({
   params: {
     postId: post.id,
   },
   props: {
     post,
   },
 }));
}

// Get article detail information
const { post } = Astro.props;
---

<Layout title={post.data.title} description={post.data.description}>
 <main>
   <h1 class="title">{post.data.title}</h1>
   <p class="publishedAt">Published at: {post.data.publishedAt}</p>
   <img src={post.data.heroImage.url} alt={post.data.heroImage.alt} />
   <div class="post" set:html={post.data.body}></div>
 </main>
</Layout>

<style>
 main {
   margin: auto;
   padding: 1em;
   max-width: 60ch;
 }
 img {
   width: 100%;
   height: auto;
 }
</style>
Enter fullscreen mode Exit fullscreen mode

getStaticPaths is used to specify what values this dynamic path can take.

Also, since the rich editor in microCMS returns an HTML string as-is, we use set:html to render the HTML directly on the screen.

<div class="post">{post.data.body}</div>
Enter fullscreen mode Exit fullscreen mode

If you write it like the example above, the HTML part will be escaped and displayed as plain text on the screen, so please be careful.

The related documentation is as follows.

I will explain later why we pass title and description as properties to the <Layout> tag.

Once you have completed the code above, the detail page will also be displayed.

Try changing the submitted content in microCMS and confirm that the article display also changes.

Reflecting Metadata

Let’s reflect the title and description defined in microCMS in the metadata of the web page.

In Astro, the common layout for pages is defined in Layout.astro, and this file also contains the HTML meta tags.

Earlier, we passed title and description as properties to the <Layout> tag on the blog detail page. Now, let’s retrieve those values and set them in the meta tags.

Edit Layout.astro as follows.

---
const { title = "My Blog", description = "My Blog Description" } = Astro.props;
---
<!doctype html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width" />
        <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
        <link rel="icon" href="/favicon.ico" />
        <meta name="generator" content={Astro.generator} />
        <meta name="description" content={description} />
        <title>{title}</title>
    </head>
    <body>
        <slot />
    </body>
</html>

<style>
    html,
    body {
        margin: 0;
        width: 100%;
        height: 100%;
    }
</style>
Enter fullscreen mode Exit fullscreen mode

With this change, when you access a detail page, the title and description will be reflected according to that page.

On the list page, we do not pass anything to the <Layout> tag, so the default values, title = "My Blog" and description = "My Blog Description", will be used.

Hosting and Publishing the Site

Now that we can display both the blog article list and detail pages, let’s publish the site.

First, let’s understand how to build and preview a site created with Astro.

Building the website is very simple. You only need to run one command.

npm run build
Enter fullscreen mode Exit fullscreen mode

If the build succeeds, the site will be output to ./dist.

You can check the output site with the following command.

npm run preview
Enter fullscreen mode Exit fullscreen mode

Now that we understand the basics, let’s publish the site using a hosting service.

The files generated after the build are simple HTML, CSS, and other static files, so you can host them almost anywhere.

However, several services are explained in detail in the official documentation.

https://docs.astro.build/en/guides/deploy/

Preparing a GitHub Repository

If you connect GitHub to your hosting service, builds and deployments can run automatically whenever you update the source code.

First, let’s prepare a GitHub repository.

Go to GitHub and select New repository from the + button in the header.

Enter astro-microcms-blog as the repository name, and set the visibility to Private.

If you want to publish the source code as well, Public is also fine.

Return to your Astro project and run the following Git commands in the terminal.

git add .
git commit -m "first commit"
git branch -M main
git remote add origin git@github.com:{your-username}/astro-microcms-blog.git
git push -u origin main
Enter fullscreen mode Exit fullscreen mode

If you can push successfully, you are done.

Hosting on Vercel

Next, let’s connect Vercel with the repository we just created.

We will use Vercel, a hosting service operated by Vercel Inc., the company behind Next.js.

Please sign up in advance.

Click New Project on the dashboard.

Then, select the repository you created this time and click Import under Import Git Repository.

There is one important thing to note here.

You need to set the Environment Variables highlighted in the red box.

The environment variables you set earlier were not pushed to Git, so Vercel does not know about them.

Therefore, you need to pass them directly to Vercel.

Set the following two values that you wrote in .env.

  • MICROCMS_API_KEY
  • MICROCMS_SERVICE_DOMAIN

Then click Deploy.

If the deployment succeeds, you will see a screen like the one below.

Click the site preview shown on the screen, and you can access the URL actually hosted on Vercel.

Connecting microCMS and Vercel

With the current settings, even if you update an article in microCMS, the production website will not be updated.

This is because, for a static site, the content is not reflected in the actual production environment unless the site is built again.

So, we will use a Webhook to trigger a build whenever an article is updated.

In the Vercel dashboard, open the project you deployed earlier.

Go to Settings > Git > Deploy Hooks and create a Webhook.

Set the name to microCMS and specify the main branch.

Then, click Create Hook.

A Webhook URL will be issued, so copy it.

Next, set the issued Webhook in the microCMS admin dashboard.

Open API Settings > Webhook for the blog you created earlier.

Click the + Add button and select Vercel.

Paste the Webhook URL you copied from Vercel into the Webhook URL field.

Set the other items as shown in the image below.

Now, when you update an article from microCMS, a Vercel build will start via the Webhook, and the content will be reflected in the production environment.

This completes the so-called Jamstack architecture.

Conclusion

In this article, we built a blog using Astro and microCMS.

By combining Astro’s fast static site generation with microCMS as a headless CMS, we were able to create a blog where content can be managed from an intuitive admin dashboard while still keeping the frontend simple and highly performant.

We also covered the full flow from setting up an Astro project, creating a microCMS API, fetching content with Astro Content Collections, generating article detail pages with dynamic routing, and finally deploying the site to Vercel. By connecting microCMS and Vercel with a Webhook, published content can automatically trigger a new deployment, making the site easier to maintain in a real-world workflow.

This setup is a good starting point for many types of content-driven websites, not only blogs but also documentation sites, news pages, landing pages, and portfolios.

From here, you can continue improving the site by adding styles, categories, tags, pagination, SEO settings, preview functionality, or search features.

Have fun customizing your blog and building your own content-driven website with Astro and microCMS!

Source: dev.to

arrow_back Back to Tutorials