← back
How I setup my website with Astro
Ditching NextJS, using MDX & more...

1. Introduction

I had previously written my website using NextJS. However, the lack of proper MDX support (At the time of writing, NextJS 13.4.10 had experimental support for MDX) was not ideal.

    /** @type {import('next').NextConfig} */
    const nextConfig = {
      experimental: {
        mdxRs: true,

    const withMDX = require("@next/mdx")();
    module.exports = withMDX(nextConfig);

I had heard great things about Astro, and the docs were a lot more oriented towards hosting / managing content, so this was a great opportunity for me to learn a new framework.

2. Getting Started

The first step is setting up an Astro project - with npm create astro@latest. Reading about the project structure was also helpful.
The basics

  • content: Contains all the blogs or whatever docs to host on the website.
  • pages: Contains all the routes. Similar to the pages folder in NextJS.
  • layouts: The base structure for the blog / home page. For now I just have a Layout.astro, but having a custom Blog.astro file can give a unique and consistent look for the blog pages.

3. Customizing

The next step was figuring out the blog should look like. I went with a brief description + some of my projects + a blog section to start with. To keep things simple, I just have a / page for my website + pages for the blog entries.

4. Writing blogs

Astro is really good at handling MDX, so writing blogs is as simple a creating a (markdown) entry in the content/blog folder. Its is recommended to a config.ts. This is so that Astro can understand the content - i.e content collections.

This way, different content types like blogs, newsletters, projects etc., can have a different structure. For example, this is my blog content structure

  // zod!
  import { z, defineCollection } from "astro:content";

  // define what properties a blog should have
  const blog = defineCollection({
    type: "content",
    schema: z.object({
      title: z.string(),
      date: z.string(),
      description: z.string(),
      isDraft: z.boolean().optional().default(false),

  // add more collections and export!
  export const collections = {

Defining the structure of a blog helps to do a some cool stuff:

  • if isDraft is set to true, the blogs can be hidden until they’re done
  • order blogs based on the date

This can be done by extracting the props in the BlogRow.astro page.

  const {
    post: {
      data: { title, date, isDraft },
  } = Astro.props;

For example, when rendering the list of blogs

  • Create a component that shows the blog title + date. This is BlogRow.astro in my case.
  • Extract the props like above, and use them to filter or alter the way the blog is displayed.

In the main index.astro, each blog is rendered like it was any react component. The props are the ones defined in the Blog Schema (hence its importance).

  const blogs = await getCollection("blog")

    {blogs.map((post) => <BlogRow {post} />)}

5. Deploying


Anything more is overkill for just starting off. I bought my domain off Google Domains (RIP), but will switch to [Cloudflare](https://www.cloudflare.com/products/registrar/) soon.

Closing Thoughts

I really liked my first foray into the Astro ecosystem

  • its stable, and there is a developed ecosystem around markdown support
  • its API’s are intuitive and easy to use

I will be using Astro from here on for static sites.

Thanks for reading! Want to read more like this? Read CLI-mbing to sucess
Source code for my website here.