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 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 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.
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 }; 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