Building My Portfolio with Astro.js: Architecture, Performance, and DX

January 2026
5 min read
Milan Praz

Astro js - Workflow

Modern content-driven websites demand strong performance, clear structure, and a great developer experience. Astro approaches this problem differently from traditional frameworks by treating content as data, not pages.

Understanding this mental model is the key to using Astro effectively.

The Big Picture

In Astro, Markdown files are not routes by default.

Instead, Astro parses .md and .mdx files at build time and converts them into typed JavaScript objects that your application can consume.

Think of the pipeline like this:

Markdown Files
↓
Astro Content Collection
↓
Typed JS objects
↓
Usedlikedatabase records

This approach eliminates the need for a CMS or API layer while still giving you structure, validation, and type safety.

Your content behaves more like a local, version-controlled database than a set of static pages.

How Astro Sees Your Project Structure

Astro discovers content based on convention.

A typical setup looks like this:


src/
└─ content/
└─ blog/
├─first-post.md
├─second-post.md
├─ third-post.md
└─using-mdx.mdx

Here’s how Astro interprets this:

  • blog becomes a collection name

  • Each Markdown or MDX file becomes one content entry

  • The file name becomes the unique ID for that entry

Example:


first-post.md → id: "first-post"

This ID is later used for routing, linking, and fetching content.

Content Collections: The Backbone

Astro content collections are defined in a single configuration file.

// src/content/config.ts
import { defineCollection, z }from'astro:content';

exportconst collections = {
blog:defineCollection({
schema: z.object({
title: z.string(),
pubDate: z.date(),
heroImage: z.optional(z.any()),
    }),
  }),
};

This file does several critical things:

  • Registers the blog collection

  • Defines the required frontmatter structure

  • Validates every Markdown file at build time

  • Provides full TypeScript inference

If any Markdown file fails this schema, the build fails immediately — no silent errors.

A Markdown File Becomes a Data Record

A Markdown File Becomes a Data Record

Example first-post.md:

---
title: My First Post
pubDate: 2025-01-12
heroImage: ../assets/blog-hero.png
---

This is the content of the post.

Astro splits this into:

Frontmatter → Structured Data

{
title:"My First Post",
pubDate:Date,
heroImage:ImageMetadata
}

Markdown Body → Renderable Content

The body remains Markdown, but Astro compiles it into a renderable component.

Markdown Body → Renderable Component

{
title:"My First Post",
pubDate:Date,
heroImage:ImageMetadata
}

Fetching Content with getCollection

At build time, you can fetch content like this:

const posts = awaitgetCollection('blog');

This returns an array of fully typed objects:

[
  {
id:"first-post",
slug:"first-post",
body:"...markdown content...",
data: {
title:"My First Post",
pubDate:Date,
heroImage:ImageMetadata
    },
render:() => {...}
  },
  ...
]

Important things to note:

  • This happens at build time

  • No API calls

  • No runtime database

  • No performance overhead

Astro statically analyzes your content and ships only what’s needed.

No API call. No database. Just static analysis.

Eg:

 {
    id: 'markdown-style-guide',
    data: {
      title: 'Markdown Style Guide',
      description: 'Here is a sample of some basic Markdown syntax that can be used when writing Markdown content in Astro.',
      pubDate: 2024-06-18T18:15:00.000Z,
      heroImage: [Object]
    },
    body: 'Here is a sample of some basic Markdown syntax that can be used when writing Markdown content in Astro.\n' +
      '\n' +
      '## Headings\n' +
      '\n' +
      'The following HTML `<h1>`—`<h6>` elements represent six levels of section headings. `<h1>` is the highest section level while `<h6>` is the lowest.\n' +
      '\n' +
      '# H1\n' +
      '\n' +
      '## H2\n' +
      '\n' +
      '### H3\n' +

Why This Model Works So Well

This workflow gives you:

  • CMS-like structure without complexity

  • Type safety for content

  • Excellent performance

  • Git-based content versioning

  • Zero runtime cost

Astro’s content system is ideal for blogs, documentation, portfolios, and knowledge bases where content quality and performance matter.