A beginners guide to Astro.js for static sites and blogs

Getting Started with Astro
4 mins

Getting Started with Astroh1

Hello! I’m Ahmet Zeybek, a full stack developer passionate about building fast, efficient web applications. Recently, I migrated my personal blog to Astro.js, and it transformed my workflow. If you’re tired of heavy JavaScript bundles for simple sites, Astro is a breath of fresh air. In this guide, I’ll walk you through why I chose Astro, how to set it up, key features like content collections and islands, and tips for optimal performance. Whether you’re building a blog, portfolio, or docs site, Astro makes it simple and speedy.

Why Astro?h2

Astro is an all-in-one static site builder designed for content-driven websites. Unlike traditional frameworks like Next.js or Gatsby that ship large JS bundles, Astro prioritizes performance with its “zero JavaScript by default” philosophy. Here’s what hooked me:

  • Static-First Rendering: Pages are pre-built as HTML at build time, leading to lightning-fast loads (often under 100ms).
  • Islands Architecture: Interactive components (e.g., a React search bar) are “islands” that hydrate only when needed – no full-page JS.
  • Framework Agnostic: Mix React, Vue, Svelte, or even vanilla JS in the same project.
  • MDX Support: Write content in Markdown with embedded JSX for dynamic elements like components or embeds.
  • Built-in Optimizations: Automatic image optimization, CSS minification, and partial hydration.

For my blog, Astro reduced my bundle size from 500KB to ~10KB while keeping interactive features like animations. It’s perfect for developers who want control without bloat.

Setup Stepsh2

Getting started is straightforward. Prerequisites: Node.js 18+ and a package manager like pnpm or npm.

1. Create a New Projecth3

Run the CLI to scaffold:

Terminal window
npm create astro@latest my-astro-blog
cd my-astro-blog
npm install

This sets up a basic structure with src/pages/, src/components/, and astro.config.mjs.

2. Add Integrationsh3

Astro shines with plugins. For a blog, add Tailwind for styling and React for components:

astro.config.mjs
import { defineConfig } from 'astro/config'
import react from '@astrojs/react'
import tailwind from '@astrojs/tailwind'
export default defineConfig({
integrations: [react(), tailwind()],
markdown: {
shikiConfig: {
theme: 'github-dark', // Or your preferred theme
},
},
})

Install dependencies:

Terminal window
npx astro add react tailwind

3. Run Development Serverh3

Terminal window
npm run dev

Visit http://localhost:4321 – your site is live with hot reloading!

4. Build and Deployh3

Terminal window
npm run build # Outputs to /dist
npm run preview # Local preview of build

Deploy to Vercel, Netlify, or GitHub Pages with one command – Astro generates static files.

Content Collections: Structured Datah2

Astro’s content collections make managing blog posts easy. Define schemas for validation and querying.

Setuph3

In src/content/config.ts:

import { z, defineCollection } from 'astro:content'
const blogCollection = defineCollection({
schema: z.object({
title: z.string(),
description: z.string(),
pubDate: z.date(),
tags: z.array(z.string()),
author: z.string().default('Ahmet Zeybek'),
cover: z
.object({
src: z.string(),
alt: z.string(),
})
.optional(),
pinned: z.boolean().default(false),
}),
})
export const collections = {
blog: blogCollection,
}

Creating a Posth3

Posts go in src/content/blog/my-post.mdx:

---
title: 'My Astro Journey'
description: 'First steps with Astro'
pubDate: 2024-10-02
tags: ['Astro', 'Blogging']
cover:
src: '/images/astro-cover.jpg'
alt: 'Astro logo'
---
# My Astro Journey
This is my first MDX post in Astro. It's mixing Markdown with JSX!
<Alert type="info">Astro rocks!</Alert>

Querying Collectionsh3

In a page (src/pages/blog/index.astro):

---
import { getCollection } from 'astro:content'
const posts = await getCollection('blog')
const sortedPosts = posts.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf())
---
<ul>
{
sortedPosts.map((post) => (
<li>
<a href={`/blog/${post.slug}`}>{post.data.title}</a>
<p>{post.data.description}</p>
</li>
))
}
</ul>

This auto-generates slugs and provides type safety.

Islands and MDX: Interactive Contenth2

Islands Architectureh3

Islands allow partial hydration. For example, embed a React counter in a static page:

src/pages/index.astro
<html>
<body>
<h1>Static Content</h1>
<p>This is pre-rendered HTML.</p>
<!-- Island: Hydrates only this part -->
<MyReactCounter client:load />
</body>
</html>

MyReactCounter.jsx (in src/components/):

import { useState } from 'react'
export default function Counter() {
const [count, setCount] = useState(0)
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
)
}

Only the counter JS loads – the rest is static!

MDX for Rich Postsh3

MDX lets you embed components in Markdown. Install @astrojs/mdx:

Terminal window
npx astro add mdx

In a post:

# Hello MDX
This is Markdown.
import { MyComponent } from '../components/MyComponent.jsx'
<MyComponent message="From MDX!" />

Transforms into dynamic content without full JS.

Code Snippets: Pages and Configh2

Custom Page with Layouth3

src/layouts/BlogLayout.astro:

---
// Props for dynamic title
const { title } = Astro.props
---
<html>
<head>
<title>{title}</title>
</head>
<body>
<header>
<nav>Blog Nav</nav>
</header>
<main>
<slot />
<!-- Page content here -->
</main>
<footer>Footer</footer>
</body>
</html>

Use in page:

src/pages/blog/[...slug].astro
---
import BlogLayout from '../../layouts/BlogLayout.astro'
import { getEntry } from 'astro:content'
const { slug } = Astro.params
const post = await getEntry('blog', slug)
const { Content } = await post.render()
---
<BlogLayout title={post.data.title}>
<article>
<h1>{post.data.title}</h1>
<Content />
</article>
</BlogLayout>

Astro Config for SEOh3

astro.config.mjs:

export default defineConfig({
site: 'https://yourblog.com',
integrations: [react(), tailwind()],
vite: {
ssr: {
noExternal: ['some-lib'], // SSR for specific packages
},
},
markdown: {
remarkPlugins: [remarkMath],
rehypePlugins: [rehypeKatex],
},
})

Performance Tipsh2

Astro is fast out-of-the-box, but optimize further:

  • Images: Use astro:assets for optimization – auto WebP, lazy loading.
  • Critical CSS: Inline above-the-fold styles.
  • Preload Fonts: <link rel="preload" as="font" ...>.
  • Search: Integrate Pagefind for client-side search without JS bloat.
  • Analytics: Add Plausible or Google Analytics as islands.

Benchmark: My blog scores 100/100 on Lighthouse after Astro migration.

Pitfall: Overusing islands – keep static where possible.

Resources for Further Learningh2

  • Official Docs: Astro Docs
  • Tutorials: freeCodeCamp Astro course, YouTube “Astro in 100 Seconds”.
  • Communities: Astro Discord, Reddit r/astrojs.
  • Books/Tools: “Static Site Generators” guides; VS Code Astro extension.
  • My Project: Check this blog’s source on GitHub for real-world examples.

Conclusionh2

Astro has revolutionized how I build static sites – faster, simpler, and more fun. From setup to deployment, it’s developer-friendly without sacrificing power. If you’re starting a blog or portfolio, give Astro a try – you won’t go back. What’s your first Astro project? Share in the comments!