Back

Understanding Astro Project Structure: Data, Content, and Lib Directories

February 20, 2024

3 min read

In an Astro project, the src/ directory is the main source folder where most of your project’s logic, components, and content reside. Within src/, you’ll often see the following directories:

src/
β”œβ”€β”€ πŸ“‚ content/           # Content Collections
β”‚   β”œβ”€β”€ πŸ“ blog/
β”‚   └── πŸ“ projects/
β”œβ”€β”€ πŸ“‚ data/             # Static data
β”‚   β”œβ”€β”€ πŸ“„ site-config.ts
β”‚   └── πŸ“„ navigation.ts
└── πŸ“‚ lib/             # Utilities and helpers
    β”œβ”€β”€ πŸ“ utils/
    β”œβ”€β”€ πŸ“ hooks/
    └── πŸ“ types/

πŸ“‚ src/data/ β†’ Static & Structured Data

The data directory is used for storing structured data that doesn’t change dynamically but is still separate from your content files. This is useful for things like:

πŸ”Ή Example

src/data/team.json
[
  { "name": "Alice", "role": "Developer" },
  { "name": "Bob", "role": "Designer" }
]

πŸ”Ή Usage in Astro

src/pages/team.astro
---
import team from "../data/team.json";
---
<ul>
  {team.map(person => (
    <li>{person.name} - {person.role}</li>
  ))}
</ul>

πŸ“‚ src/content/ β†’ Content Collections

This is the recommended place for Markdown-based content collections, such as:

Astro’s Content Collections API uses this directory to define and validate structured content.

πŸ”Ή Example

src/content/blog/my-first-post.md
---
title: "My First Blog Post"
date: "2025-02-21"
author: "Christian"
---
This is my first blog post in Astro!

πŸ”Ή Usage in Astro

src/pages/blog.astro
---
import { getCollection } from "astro:content";
const posts = await getCollection("blog");
---
<ul>
  {posts.map(post => (
    <li><a href={post.slug}>{post.data.title}</a></li>
  ))}
</ul>

πŸ”Ή Config

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

const blog = defineCollection({
  schema: z.object({
    title: z.string(),
    date: z.string(),
    author: z.string(),
  }),
});

export const collections = { blog };

πŸ“Œ Why use src/content/ instead of src/data/?


πŸ“‚ src/lib/ β†’ Utility & Helper Functions

This is where you store reusable functions, scripts, and utilities that don’t belong to any specific page or component. It’s useful for:

Formatters

Common utilities include date and string formatters:

src/lib/formatters.ts
export const formatDate = (date: Date): string => {
  return new Date(date).toLocaleDateString('en-US', {
    year: 'numeric',
    month: 'long',
    day: 'numeric'
  });
};

export const slugify = (text: string): string => {
  return text
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/(^-|-$)+/g, '');
};

Metadata Utilities

Helper functions for managing page metadata:

src/lib/metadata.ts
interface PageMeta {
  title: string;
  description: string;
  image?: string;
}

export const generateMeta = ({ title, description, image }: PageMeta) => ({
  title: `${title} | My Site`,
  description,
  ogImage: image || '/default-og.png',
  // Add more metadata as needed
});

πŸ”Ή Example

src/lib/formatDate.ts
export function formatDate(date: string): string {
  return new Date(date).toLocaleDateString("en-US", {
    year: "numeric",
    month: "long",
    day: "numeric",
  });
}

πŸ”Ή Usage in an Astro Component

src/pages/blog.astro
---
import { formatDate } from "../lib/formatDate";
import { getCollection } from "astro:content";
const posts = await getCollection("blog");
---
<ul>
  {posts.map(post => (
    <li>{formatDate(post.data.date)} - {post.data.title}</li>
  ))}
</ul>

πŸš€ Final Takeaways

DirectoryPurpose
src/data/Stores structured data (JSON, YAML, CSV, etc.) for things like team members, pricing, etc.
src/content/Stores Markdown-based content collections (blogs, docs, FAQs) with type validation.
src/lib/Stores reusable utility functions and custom plugins/helpers.

Each directory serves a specific purpose in an Astro project, helping maintain a clean and organized structure.

Let me know if you need further clarification! πŸš€