lexington®
Use code LEX35 at checkout
7k+ customers.
Using `astro-seo` to Simplify SEO in Astro Projects
Learn how to install and configure the `astro-seo` component in your Astro site—streamline titles, meta tags, Open Graph and Twitter cards
Published on August 29, 2025 by Michael AndreuzzaAstro is already blazing fast and inherently SEO-friendly thanks to its static-first architecture and minimal client-side JavaScript. But managing SEO metadata—titles, descriptions, Open Graph, Twitter cards, structured data—can become repetitive and error-prone.
Enter astro-seo: a smart, flexible component that centralizes all your SEO needs in one spot. Think of it as your own SEO checklist packaged into a reusable component.
Quick i nstallation
Install via your preferred package manager:
npm install astro-seo
# or
yarn add astro-seo
# or
pnpm add astro-seo
Step 1: Define site-wide defaults
Create a file src/constants/siteData.json to store your default metadata:
{
"default": {
"title": "Lexington Themes",
"description": "Fast Astro + Tailwind templates.",
"openGraph": {
"basic": {
"title": "Lexington Themes",
"type": "website",
"image": "https://lexingtonthemes.com/og-default.jpg",
"url": ""
},
"optional": {
"siteName": "Lexington Themes"
}
},
"twitter": {
"card": "summary_large_image",
"site": "@lexingtonthemes",
"creator": "@lexingtonthemes"
},
"noindex": false,
"nofollow": false
},
"pages": {
"about": {
"title": "About · Lexington Themes",
"description": "About Lexington Themes and what drives us.",
"openGraph": {
"basic": {
"title": "About Lexington Themes",
"type": "website",
"image": "https://lexingtonthemes.com/og-about.jpg",
"url": ""
}
}
}
}
}
Step 2: Set up BaseLayout.astro with merged SEO ,ogic
In src/layouts/BaseLayout.astro, merge site defaults with per-page overrides:
---
import { SEO } from 'astro-seo';
import siteData from '../constants/siteData.json';
const { seo = {} } = Astro.props;
const merged = {
...siteData.default,
...seo,
openGraph: {
basic: {
...siteData.default.openGraph.basic,
...seo.openGraph?.basic,
url: Astro.url.href
},
optional: siteData.default.openGraph.optional
},
twitter: {
...siteData.default.twitter,
...seo.twitter
}
};
---
<html lang="en">
<head>
<SEO {...merged} />
</head>
<body>
<slot />
</body>
</html>
Now, any page wrapped in this layout will automatically get SEO defaults unless overridden explicitly.
Step 3: Example of a static page (about.astro)
---
import BaseLayout from '../layouts/BaseLayout.astro';
import siteData from '../constants/siteData.json';
const seo = siteData.pages.about;
---
<BaseLayout seo={seo}>
<h1>About Lexington Themes</h1>
<p>Learn about our mission and journey.</p>
</BaseLayout>
This makes the “About” page pick up its own title and description while applying site-wide defaults where needed.
Step 4: Dynamic blog post SEO
---
import BaseLayout from '../layouts/BaseLayout.astro';
import { getEntryBySlug } from 'astro:content';
const { slug } = Astro.params;
const post = await getEntryBySlug('blog', slug);
const seo = {
title: post.data.title,
description: post.data.excerpt,
openGraph: {
basic: {
title: post.data.title,
type: "article",
image: post.data.cover,
url: Astro.url.href
},
article: {
publishedTime: post.data.published,
tags: post.data.tags
}
}
};
---
<BaseLayout seo={seo}>
<article>
<h1>{post.data.title}</h1>
<p><em>Published: {post.data.published}</em></p>
{post.content}
</article>
</BaseLayout>
Each blog post now carries its own unique SEO metadata (title, excerpt, cover image, publication date, and tags).
Step 5: Validation & testing
- Use Lighthouse’s SEO audit in DevTools to check for missing tags.
- Preview social sharing with tools like Facebook Sharing Debugger and Twitter Card Validator.
- Ensure canonical URLs are correct to avoid duplicate content.
TL;DR
- Define global SEO defaults in
siteData.json. - Use
BaseLayout.astrowithastro-seoto centralize SEO logic. - Allow pages to override defaults selectively.
- Easily scale SEO across static, static-generated, and dynamic page types.
- Streamline SEO setup while keeping your pages metadata-rich, consistent, and error-free.
/Michael Andreuzza