Brand & SEO
Identity kit
AtroUI structures design, brand configuration, and technical SEO as a unified pipeline. Most component registries stop at CSS variables. We provide a complete Brand & SEO Identity Kit — so when you install headers, footers, JSON-LD, or favicons, they pull from a single source of truth and stay in sync.
1. Core brand config (getBrand)
Instead of hardcoding your product name or canonical URLs across headers, footers, and SEO scripts, we configure them in a single place. Install the brand helper:
npx shadcn@latest add @atroui/brandThis drops lib/brand.ts into your project, resolving environmental overrides or default fallbacks dynamically:
// lib/brand.ts
export function getBrand() {
return {
name: process.env.NEXT_PUBLIC_SITE_NAME || "My SaaS",
domain: process.env.NEXT_PUBLIC_SITE_DOMAIN || "mysaas.com",
email: process.env.NEXT_PUBLIC_SITE_EMAIL || "hello@mysaas.com",
siteUrl: process.env.NEXT_PUBLIC_SITE_URL || "https://www.mysaas.com",
tagline: "Own the UI, borrow the API.",
}
}To completely rebrand your site chrome, legal notices, and structured data, you only need to configure your environment variables:
NEXT_PUBLIC_SITE_NAME="AstroSaaS"
NEXT_PUBLIC_SITE_DOMAIN="astrosaas.com"
NEXT_PUBLIC_SITE_EMAIL="team@astrosaas.com"
NEXT_PUBLIC_SITE_URL="https://www.astrosaas.com"2. Schema.org structured data (JSON-LD)
Google and other search engines utilize Schema.org JSON-LD to display rich snippets, star-ratings, and nest directories in the SERP. AtroUI offers headless schema components that automatically read from your brand config. Install the schema package:
npx shadcn@latest add @atroui/json-ldThis registers headless script blocks inside your component catalog. Combine them within your root App Router layout or individual page files:
// app/layout.tsx
import { SiteGraphJsonLd } from "@/components/seo/json-ld"
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<SiteGraphJsonLd />
{children}
</body>
</html>
)
}For technical docs or long-form developer articles, inject article metadata onto pages dynamically:
// app/blog/[slug]/page.tsx
import { ArticleJsonLd } from "@/components/seo/json-ld"
export default function BlogPost({ post }) {
return (
<article>
<ArticleJsonLd
title={post.title}
description={post.description}
slug={post.slug}
date={post.date}
basePath="/blog"
/>
<h1>{post.title}</h1>
</article>
)
}3. Next.js metadata and canonical paths
Search engines penalize duplicate path strings. To prevent index pollution, ensure a stable metadataBase is set in the root layout metadata so relative paths resolve to the absolute canonical URL automatically.
// app/layout.tsx
import { Metadata } from "next"
import { getBrand } from "@/lib/brand"
const brand = getBrand()
export const metadata: Metadata = {
metadataBase: new URL(brand.siteUrl),
title: {
default: `${brand.name} - ${brand.tagline}`,
template: `%s · ${brand.name}`,
},
description: "High-performance dark-first component catalog.",
alternates: {
canonical: "/",
},
}4. 2026 Favicon and SERP checklist
Modern search results display your brand favicon right next to your snippet link. If you only provide a legacy favicon, Google may display a generic globe, lowering organic click-through rates.
To configure your favicons in a Next.js App Router project using AtroUI specifications, place these in your public/ directory:
/icon.svg— standard scalable icon, used by modern browser tabs./favicon-48.png— 48x48 PNG icon specifically required by Google Search crawler./favicon-96.png,/favicon-192.png— high-dpi assets./apple-touch-icon.png— 180x180 mobile app tile.
Then, reference them absolutely via relative URLs in your layout metadata:
// app/layout.tsx
export const metadata = {
// ...
icons: {
icon: [
{ url: "/icon.svg", type: "image/svg+xml" },
{ url: "/favicon-48.png", sizes: "48x48", type: "image/png" },
{ url: "/favicon-96.png", sizes: "96x96", type: "image/png" },
{ url: "/favicon-192.png", sizes: "192x192", type: "image/png" },
{ url: "/favicon.ico", sizes: "48x48" },
],
apple: [
{ url: "/apple-touch-icon.png", sizes: "180x180", type: "image/png" },
],
},
}5. Sitemap and robots generation
App Router supports automated dynamic sitemaps and search crawler instructions natively. Build your dynamic crawl tree using the dynamic sitemap helper:
// app/sitemap.ts
import type { MetadataRoute } from "next"
import { getBrand } from "@/lib/brand"
export default function sitemap(): MetadataRoute.Sitemap {
const brand = getBrand()
const lastModified = new Date()
return [
{
url: brand.siteUrl,
lastModified,
changeFrequency: "weekly",
priority: 1,
},
{
url: `${brand.siteUrl}/docs`,
lastModified,
changeFrequency: "monthly",
priority: 0.8,
},
]
}And drop crawler rules into app/robots.ts:
// app/robots.ts
import type { MetadataRoute } from "next"
import { getBrand } from "@/lib/brand"
export default function robots(): MetadataRoute.Robots {
const brand = getBrand()
return {
rules: {
userAgent: "*",
allow: "/",
},
sitemap: `${brand.siteUrl}/sitemap.xml`,
host: brand.siteUrl,
}
}SEO Discipline: Brand ≠ CONTENT
AtroUI maintains a strict division of data to avoid typical template mistakes:
- Brand Profile — configured globally via environment variables (getBrand), powering headers, footers, JSON-LD, sitemaps, and default mail handles.
- Section Copy (CONTENT) — configured locally at the top of individual block files, representing the exact words displayed in marketing components (e.g. `DEFAULT_BRAND` on dynamic heroes).
This boundary ensures your product is immediately indexable on your production URL, with no generic template strings leaking into Google's index.