Getting Started with Astro

An interactive guide to building your first Astro application. Explore the core concepts and get your project up and running in minutes.

1. Setting Up a New Astro Project

Getting an Astro project up and running is simple with the official command-line interface (CLI). First, make sure you have Node.js (version 18.14.1 or higher) installed. Then, open your terminal and run the following command:

# create a new project with npm
npm create astro@latest

This command kicks off a setup wizard that will guide you through a few questions:

  1. Where should we create your new project? You can type . to use the current directory or provide a new folder name (e.g., ./my-astro-site).
  2. Which template would you like to use? For this tutorial, select the "Empty" template to start from scratch.
  3. Would you like to install dependencies? Press y to let Astro install the necessary packages.
  4. Would you like to initialize a new git repository? Press y if you plan to use Git for version control.

TypeScript Support by Default

Astro is a JavaScript framework that comes with first-class TypeScript support out of the box. During the setup wizard, you'll be asked to choose a TypeScript strictness level (Strict, Strictest, or Relaxed). You can start writing TypeScript in your .astro and .ts files immediately with no extra configuration. Of course, if you prefer, you can write plain JavaScript instead—Astro supports both seamlessly.

Using Command-Line Flags

For automated setups, you can bypass the interactive wizard by providing flags directly in the command line. If using npm, you must add -- before the flags.

  • --template <name>: Specifies a starter template (e.g., minimal, blog).
  • --install or --no-install: Skips or forces dependency installation.
  • --git or --no-git: Skips or forces Git repository initialization.
  • --skip-houston: Skips the wizard entirely.

For example, to create a new project named my-silent-app using the minimal template and skipping installation, you would run:

npm create astro@latest my-silent-app -- --template minimal --skip-houston --no-install

Once the setup is complete, navigate into your new project directory and start the development server:

cd your-project-name
npm run dev

You can now view your new site running live at http://localhost:4321.

2. How to Add a Page

Astro uses a file-based routing system, which means every .astro, .md, or .html file you create in the src/pages/ directory automatically becomes a page on your website. Let's create an "About" page:

  1. Create a new file inside the src/pages/ directory named about.astro.
  2. Add the following content to your new file:
---
// src/pages/about.astro
---
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width" />
  <title>About Me</title>
</head>
<body>
  <h1>About Me</h1>
  <p>This is the about page for my new Astro site!</p>
  <a href="/">Go back home</a>
</body>
</html>

Now, if you visit http://localhost:4321/about in your browser, you will see your new page. It's that simple!

3. How to Add a Component

Components are reusable pieces of UI that you can use across multiple pages. It's a best practice to keep them in the src/components/ directory. Let's create a reusable Header component:

  1. Create a new directory named src/components/.
  2. Inside src/components/, create a new file named Header.astro.
  3. Add the following code to Header.astro:
---
// src/components/Header.astro
export interface Props {
	title: string;
}

const { title } = Astro.props;
---
<header>
  <h1>{title}</h1>
  <nav>
    <a href="/">Home</a>
    <a href="/about">About</a>
  </nav>
</header>
<style>
  header {
    background: #f7f7f7;
    padding: 1rem;
    border-bottom: 1px solid #eee;
  }
  nav a {
    margin-right: 1rem;
  }
</style>

Now, you can import and use this component in any of your pages. Let's update index.astro:

---
// src/pages/index.astro
import Header from '../components/Header.astro';
---
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width" />
  <title>My Astro Site</title>
</head>
<body>
  <Header title="Welcome to my Astro Site!" />
  <main>
    <p>This is the homepage.</p>
  </main>
</html>

4. How to Create Dynamic Routes

Dynamic routing allows you to generate pages programmatically from a single file. This is perfect for blog posts or product pages. Let's create dynamic pages for a series of blog posts.

  1. Create a file at src/pages/posts/[id].astro. The square brackets [id] signify a dynamic parameter.
  2. Add the following code. This file is responsible for fetching the data and defining which routes to generate.
---
// src/pages/posts/[id].astro
import Header from '../../components/Header.astro';

export async function getStaticPaths() {
  const posts = [
    { id: '1', title: 'My First Post', content: 'This is the content of my very first post.' },
    { id: '2', title: 'Astro is Awesome', content: 'I am really enjoying learning Astro.' },
    { id: '3', title: 'Building with Components', content: 'Components make everything so much easier.' }
  ];

  return posts.map(post => ({
    params: { id: post.id },
    props: { post },
  }));
}

const { post } = Astro.props;
---
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width" />
  <title>{post.title}</title>
</head>
<body>
  <Header title="My Blog" />
  <main style="padding: 1rem;">
    <h2>{post.title}</h2>
    <p>{post.content}</p>
  </main>
</body>
</html>

With this single file, Astro will generate three pages: /posts/1, /posts/2, and /posts/3. The getStaticPaths function returns an array of objects, where each object defines the params (the URL) and props (the data) for a specific page.

Linking to External Pages

It's important to note that dynamic routing with getStaticPaths is specifically for generating pages on your own site. It cannot be used to create redirects or links that point to external websites.

To create a dynamic list of external links, you would use a standard Astro page. In the frontmatter, you can fetch or define your list of links, and then use the .map() function in the template to render them as standard <a> tags.

For example, to create a page listing your social media profiles:

---
// src/pages/socials.astro
const socialProfiles = [
  { name: 'GitHub', url: 'https://github.com/withastro' },
  { name: 'Twitter', url: 'https://twitter.com/astrodotbuild' },
  { name: 'Discord', url: 'https://astro.build/chat' }
];
---
<html>
  <head><title>Our Socials</title></head>
  <body>
    <h1>Follow us!</h1>
    <ul>
      {socialProfiles.map(profile => (
        <li>
          <a href={profile.url} target="_blank" rel="noopener noreferrer">
            {profile.name}
          </a>
        </li>
      ))}
    </ul>
  </body>
</html>

5. How to Use Plugins (Integrations)

Astro has a powerful system for adding new features and integrations with other tools. In Astro, these are called Integrations. You can add features like React components, Tailwind CSS, and sitemaps.

You can add an official integration automatically with the astro add command. For example, to add the React integration, you would run:

npx astro add react

This command will automatically install the necessary packages and update your astro.config.mjs file.

Performance Impact

A key benefit of Astro's architecture is that most integrations are build-time only. This means they do their work during development and add zero client-side JavaScript to your published site. For example, integrations for Tailwind, sitemaps, or MDX processing won't slow down your users. Integrations for UI frameworks like React or Vue are special; they only add JavaScript to the page if you specifically mark a component as interactive using a client:* directive, giving you full control over your site's performance.

6. How to Add Tailwind CSS

Tailwind CSS is a first-class citizen in the Astro ecosystem and provides a fantastic developer experience for styling your site. You can add it using the Astro Tailwind integration:

npx astro add tailwind

This command will install Tailwind, create a tailwind.config.mjs file, and add the integration to your astro.config.mjs. You can then start using Tailwind's utility classes throughout your project.

For beautiful default typography styles for long-form content (like blog posts or this tutorial), you can use the official Tailwind CSS Typography plugin. It provides the prose classes which style your text automatically.

7. How to Add Markdown Parser Plugins

Astro's Markdown processing is highly extensible. While the MDX integration is popular for embedding components, you can also add plugins to support new syntax (like tables or footnotes) or to modify the final HTML output.

This is done using remark and rehype plugins.

  • Remark plugins transform the Markdown itself (e.g., adding support for GitHub Flavored Markdown tables with remark-gfm).
  • Rehype plugins manipulate the final HTML output (e.g., automatically adding ids to headings for anchor links).

You can add these plugins in your astro.config.mjs file. First, install the desired plugin, then import it and add it to the configuration:

// astro.config.mjs
import { defineConfig } from 'astro/config';
import remarkGfm from 'remark-gfm';

export default defineConfig({
  markdown: {
    remarkPlugins: [remarkGfm],
    // rehypePlugins: [],
  },
});

You can find extensive lists of available plugins to explore:

8. Organizing Content with Collections

For content-heavy sites, Astro provides a powerful feature called Content Collections. This is the best way to manage related content, like blog posts, by enforcing a common configuration and providing full TypeScript support.

Instead of placing posts in src/pages/, you place them in a dedicated src/content/ directory. You then define a schema that validates the front matter of each entry.

  1. Create a file at src/content/config.ts and define a schema for your blog posts. This ensures every post has a title, description, and publish date.
// src/content/config.ts
import { defineCollection, z } from 'astro:content';

const blogCollection = defineCollection({
  schema: z.object({
    title: z.string(),
    description: z.string(),
    publishDate: z.date(),
  }),
});

export const collections = {
  'blog': blogCollection,
};

  1. Move your Markdown posts into src/content/blog/. Now, Astro will validate each post against your schema.
  2. Use the getCollection() API on a page (like src/pages/blog.astro) to query all your posts and render a list.

---
// src/pages/blog.astro
import { getCollection } from 'astro:content';

const allBlogPosts = await getCollection('blog');
---
<html>
  <body>
    <h1>My Blog</h1>
    <ul>
      {allBlogPosts.map(post => (
        <li><a href={`/blog/${post.slug}/`}>{post.data.title}</a></li>
      ))}
    </ul>
  </body>
</html>

This approach provides a robust, type-safe way to manage and query your content, making it the recommended method for any project with multiple pieces of similar content.

9. Integrating with Storybook.js

Storybook is a powerful tool for developing UI components in isolation. Astro provides an official integration to make setting it up seamless.

  1. Add the integration: Run the following command in your project's terminal:
npx astro add storybook

This command will install all necessary dependencies, create configuration files in a new .storybook/ directory, and add the required scripts to your package.json.

  • Create a story: A "story" is a file that demonstrates a single state of a component. For a component located at src/components/Button.astro, you would create a story at src/components/Button.stories.js.

// src/components/Button.stories.js
import Button from './Button.astro';

export default {
  title: 'Components/Button',
};

export const Primary = () => <Button label="Primary Button" />;
export const Secondary = () => <Button label="Secondary Button" variant="secondary" />;

  • Run Storybook: Start the Storybook development server to view and interact with your components.

npm run storybook

10. How to Add PWA and Service Worker Support

You can enhance your Astro site to work offline and make it installable like a native app by turning it into a Progressive Web App (PWA). This is handled by a service worker. While you could write a service worker script manually, the recommended approach is to use the @vite-pwa/astro integration.

  1. Add the integration: Run the following command in your project's terminal:
npm install -D @vite-pwa/astro

  • Configure it:
  • After installation, you need to add and configure the integration in your astro.config.mjs file. The integration uses Google's Workbox library under the hood, giving you powerful control over caching with sensible defaults.

Handling the Web Manifest

The @vite-pwa/astro integration also handles the creation and injection of the web manifest for you. Typically, you create a base manifest.json file in your project where you define your app's name, icons, and colors. The integration then processes this file during the build and automatically adds the correct <link rel="manifest" ...> tag into the <head> of your pages. This automates a key part of the PWA setup.

11. Where to Find Information About Available Plugins

The Astro team and community maintain a large collection of official and community-built integrations. You can explore all the available options in the official integrations directory.

Explore all Astro Integrations →

This is the best place to find integrations for:

  • UI Frameworks (React, Vue, Svelte)
  • CSS & Styling (Tailwind, Sass)
  • Adapters for deploying to different hosts (Vercel, Netlify)
  • Site utilities (Sitemaps, RSS feeds)
  • And much more!