About This Project

A reference project showcasing Astro v6 with TailwindCSS v4 and type-safe Content Collections, using the native Vite plugin approach — zero CSS config files needed.

Astro v6

Astro is a web framework designed for content-driven websites. Its island architecture sends zero JavaScript by default, hydrating only the interactive components that need it. Version 6 brings improved performance, enhanced content collections with the Content Layer API, and better developer experience with tighter Vite integration. This project leverages Astro's static site generation to produce pre-rendered HTML pages that load instantly in the browser.

TailwindCSS v4

TailwindCSS v4 introduces a CSS-first configuration approach, eliminating the need for a JavaScript config file. Instead of tailwind.config.js, you configure themes and custom utilities directly in your CSS using @theme directives. The Vite plugin provides automatic content detection, so you never need to configure the content array. This project uses the @tailwindcss/vite plugin integrated directly into Astro's Vite config for the smoothest developer experience.

Content Collections

This project uses Astro's Content Layer API to manage structured content with type-safe schemas. Two collections are configured — Blog and Projects — each with Zod-validated frontmatter that provides TypeScript autocompletion and build-time validation.

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

const blog = defineCollection({
  loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/blog' }),
  schema: z.object({
    title: z.string(),
    description: z.string(),
    pubDate: z.coerce.date(),
    author: z.string().default('Astro Team'),
    tags: z.array(z.string()).default([]),
    draft: z.boolean().default(false),
  }),
});

const projects = defineCollection({
  loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/projects' }),
  schema: z.object({
    title: z.string(),
    description: z.string(),
    startDate: z.coerce.date(),
    status: z.enum(['active', 'completed', 'archived']),
    techStack: z.array(z.string()).default([]),
    featured: z.boolean().default(false),
  }),
});

export const collections = { blog, projects };

Project Structure

astro-project/
├── public/              # Static assets
│   └── favicon.svg
├── src/
│   ├── components/      # Reusable UI components
│   │   ├── FeatureCard.astro
│   │   ├── Features.astro
│   │   ├── Footer.astro
│   │   ├── Hero.astro
│   │   ├── LatestPosts.astro
│   │   └── Navbar.astro
│   ├── content/         # Content Collections
│   │   ├── blog/        # Blog posts (Markdown)
│   │   └── projects/    # Project entries (Markdown)
│   ├── layouts/         # Page layouts
│   │   ├── BlogPost.astro
│   │   ├── Layout.astro
│   │   └── ProjectPage.astro
│   ├── pages/           # File-based routing
│   │   ├── blog/
│   │   │   ├── index.astro
│   │   │   ├── [...slug].astro
│   │   │   └── rss.xml.ts
│   │   ├── projects/
│   │   │   ├── index.astro
│   │   │   └── [...slug].astro
│   │   ├── about.astro
│   │   └── index.astro
│   ├── styles/
│   │   └── global.css   # TailwindCSS v4 + Typography plugin
│   └── content.config.ts # Collection schemas
├── astro.config.mjs     # Astro + TailwindCSS Vite config
├── tsconfig.json
└── package.json