Step 1: Understanding the Basics of Astro

What is Astro? Astro is a modern web framework that allows you to build faster websites with less client-side JavaScript. It focuses on content-first websites and follows a “islands architecture” approach, where interactive components are isolated while the rest of your site remains static HTML.

Key Features:

  • Server-first architecture
  • Zero JS by default (client-side JS is opt-in)
  • Component islands
  • Supports multiple UI frameworks (React, Vue, Svelte, etc.)
  • Built-in file-based routing
  • Excellent for content-heavy sites

Step 2: Setting Up Your Development Environment

  1. Install Node.js (v16.12.0 or higher)

    • Download from nodejs.org
    • Verify installation: node -v and npm -v
  2. Create Your First Astro Project

    # Create a new project with the CLI
    npm create astro@latest
     
    # Follow the prompts to set up your project
    # Choose a starter template (recommend "Empty" for beginners)
     
    # Navigate to your project directory
    cd your-project-name
     
    # Start the development server
    npm run dev
  3. Explore Your Project Structure

    • src/: Main source code
    • src/pages/: File-based routing
    • src/components/: Reusable UI components
    • src/layouts/: Page layouts
    • public/: Static assets

Step 3: Understanding Astro Pages and Routing

  1. Create Basic Pages

    • Add a page at src/pages/about.astro
    ---
    // Front matter (JavaScript/TypeScript code)
    const pageTitle = "About Me";
    ---
     
    <!-- HTML markup -->
    <html>
      <head>
        <title>{pageTitle}</title>
      </head>
      <body>
        <h1>{pageTitle}</h1>
        <p>Welcome to my Astro site!</p>
      </body>
    </html>
  2. File-Based Routing

    • index.astro → /
    • about.astro → /about
    • blog/index.astro → /blog
    • blog/[slug].astro → Dynamic routes like /blog/post-1

Step 4: Creating Layouts and Components

  1. Create a Layout

    • Add a file at src/layouts/MainLayout.astro
    ---
    const { title } = Astro.props;
    ---
     
    <html>
      <head>
        <title>{title}</title>
      </head>
      <body>
        <nav>
          <a href="/">Home</a>
          <a href="/about">About</a>
          <a href="/blog">Blog</a>
        </nav>
        <main>
          <slot /> <!-- Content is injected here -->
        </main>
        <footer>
          <p>© 2025 My Astro Site</p>
        </footer>
      </body>
    </html>
  2. Use the Layout

    • Update src/pages/index.astro
    ---
    import MainLayout from '../layouts/MainLayout.astro';
    ---
     
    <MainLayout title="Home Page">
      <h1>Welcome to my website!</h1>
      <p>This is my awesome Astro site.</p>
    </MainLayout>
  3. Create a Reusable Component

    • Add a file at src/components/Card.astro
    ---
    const { title, description, url } = Astro.props;
    ---
     
    <div class="card">
      <h2>{title}</h2>
      <p>{description}</p>
      <a href={url}>Read more</a>
    </div>
     
    <style>
      .card {
        border: 1px solid #ddd;
        padding: 1rem;
        border-radius: 4px;
      }
    </style>
  4. Use the Component

    • In any page:
    ---
    import MainLayout from '../layouts/MainLayout.astro';
    import Card from '../components/Card.astro';
    ---
     
    <MainLayout title="Blog">
      <h1>Blog Posts</h1>
      <Card 
        title="First Post" 
        description="This is my first blog post" 
        url="/blog/first-post" 
      />
    </MainLayout>

Step 5: Styling Your Astro Site

  1. Component-Level Styles

    <style>
      h1 {
        color: navy;
      }
      
      /* Styles are automatically scoped to the component */
    </style>
  2. Global Styles

    • Create src/styles/global.css
    * {
      box-sizing: border-box;
      margin: 0;
    }
     
    body {
      font-family: sans-serif;
      line-height: 1.6;
    }
    • Import in your layout:
    ---
    import '../styles/global.css';
    ---
  3. CSS Frameworks

    • Install Tailwind CSS:
    npx astro add tailwind
    • Follow the setup instructions that appear

Step 6: Adding Content with Markdown

  1. Create Markdown Files

    • Add a file at src/pages/blog/first-post.md
    ---
    title: My First Blog Post
    pubDate: 2025-03-24
    description: This is my first blog post!
    author: Your Name
    ---
     
    # My First Blog Post
     
    This is my **first** blog post using *Astro*. It's really cool!
     
    ## Section One
     
    - List item one
    - List item two
  2. Create a Layout for Blog Posts

    • Add src/layouts/BlogPostLayout.astro
    ---
    import MainLayout from './MainLayout.astro';
    const { frontmatter } = Astro.props;
    ---
     
    <MainLayout title={frontmatter.title}>
      <article>
        <h1>{frontmatter.title}</h1>
        <p>Published on: {frontmatter.pubDate.slice(0,10)}</p>
        <p><em>{frontmatter.description}</em></p>
        <slot />
      </article>
    </MainLayout>
  3. Apply the Layout to Markdown Files

    • Update src/pages/blog/first-post.md
    ---
    title: My First Blog Post
    pubDate: 2025-03-24
    description: This is my first blog post!
    author: Your Name
    layout: ../../layouts/BlogPostLayout.astro
    ---
     
    # My First Blog Post
    ...

Step 7: Dynamic Content with the Content Collections API

  1. Set Up Content Collections

    • Create src/content/config.ts
    import { defineCollection, z } from 'astro:content';
     
    const blogCollection = defineCollection({
      schema: z.object({
        title: z.string(),
        pubDate: z.date(),
        description: z.string(),
        author: z.string(),
      }),
    });
     
    export const collections = {
      'blog': blogCollection,
    };
  2. Create Blog Posts in the Collection

    • Move blog posts to src/content/blog/first-post.md
  3. Query and Render Collection Data

    • Update src/pages/blog/index.astro
    ---
    import MainLayout from '../../layouts/MainLayout.astro';
    import { getCollection } from 'astro:content';
     
    const blogPosts = await getCollection('blog');
    ---
     
    <MainLayout title="Blog">
      <h1>All Blog Posts</h1>
      <ul>
        {blogPosts.map(post => (
          <li>
            <a href={`/blog/${post.slug}`}>{post.data.title}</a>
            <p>{post.data.description}</p>
          </li>
        ))}
      </ul>
    </MainLayout>
  4. Create a Dynamic Route for Blog Posts

    • Add src/pages/blog/[...slug].astro
    ---
    import { getCollection } from 'astro:content';
    import BlogPostLayout from '../../layouts/BlogPostLayout.astro';
     
    export async function getStaticPaths() {
      const blogEntries = await getCollection('blog');
      return blogEntries.map(entry => ({
        params: { slug: entry.slug }, 
        props: { entry },
      }));
    }
     
    const { entry } = Astro.props;
    const { Content } = await entry.render();
    ---
     
    <BlogPostLayout frontmatter={entry.data}>
      <Content />
    </BlogPostLayout>

Step 8: Adding Interactivity with Islands

  1. Create a React Component (or Vue/Svelte/etc.)

    • Install the integration: npx astro add react
    • Create src/components/Counter.jsx
    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>
      );
    }
  2. Use the Component as an Island

    • Add to a page:
    ---
    import MainLayout from '../layouts/MainLayout.astro';
    import Counter from '../components/Counter.jsx';
    ---
     
    <MainLayout title="Interactive Demo">
      <h1>Interactive Component</h1>
      <Counter client:load />
    </MainLayout>
  3. Client Directives

    • client:load: Load and hydrate the component on page load
    • client:idle: Hydrate when the browser is idle
    • client:visible: Hydrate when the component is visible
    • client:media: Hydrate when a media query is matched

Step 9: Fetching External Data

  1. Fetch Data in the Front Matter
    ---
    import MainLayout from '../layouts/MainLayout.astro';
     
    // Fetch data at build time
    const response = await fetch('https://jsonplaceholder.typicode.com/users');
    const users = await response.json();
    ---
     
    <MainLayout title="Users">
      <h1>Users List</h1>
      <ul>
        {users.map(user => (
          <li>{user.name} - {user.email}</li>
        ))}
      </ul>
    </MainLayout>

Step 10: Optimizing Your Site

  1. Image Optimization

    • Use the built-in Image component:
    ---
    import { Image } from 'astro:assets';
    import myImage from '../assets/my-image.jpg';
    ---
     
    <Image src={myImage} alt="Description" width="600" height="400" />
  2. SEO Optimization

    • Add meta tags in your layout
    • Consider installing astro-seo package
    • Create a reusable SEO component

Step 11: Deploying Your Astro Site

  1. Build Your Site

    npm run build
    • Output is in the dist/ directory
  2. Choose a Hosting Platform

    • Netlify: npx astro add netlify
    • Vercel: npx astro add vercel
    • GitHub Pages: npx astro add github
  3. Deploy

    • Follow the platform-specific instructions
    • Example for Netlify: netlify deploy --prod

Step 12: Advanced Astro Features

  1. Server-Side Rendering (SSR)

    • Enable SSR: npx astro add node
    • Update astro.config.mjs:
    export default defineConfig({
      output: 'server',
    });
  2. API Routes

    • Create src/pages/api/hello.js:
    export function GET() {
      return new Response(JSON.stringify({
        message: "Hello, World!"
      }), {
        headers: {
          "Content-Type": "application/json"
        }
      });
    }
  3. Middleware

    • Create src/middleware.js:
    export function onRequest({ request, locals }, next) {
      // Run code before the request is processed
      locals.customData = "example";
      return next();
    }

Resources for Continued Learning

  1. Official Documentation: docs.astro.build
  2. Astro Discord Community: astro.build/chat
  3. Example Projects: astro.new
  4. Astro Blog: astro.build/blog

Start with small projects to practice what you’ve learned, and gradually build more complex applications as you become more comfortable with Astro’s features and capabilities.