From fe0806a72589964964bff91b5cc795376d098ff7 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 24 Dec 2025 04:51:34 +0000 Subject: [PATCH 1/6] docs(start): add SEO guide for React and Solid frameworks Add a comprehensive SEO guide that clarifies what SEO actually means for developers and explains TanStack Start's technical SEO capabilities: - Document head management (meta tags, titles, Open Graph) - Server-side rendering for crawlability - Static prerendering for performance - Structured data (JSON-LD) for rich results - Sitemap and robots.txt generation via server routes - Best practices for technical SEO This addresses the common misconception that SEO is just a checkbox, explaining that it's about using available tools effectively. --- docs/start/config.json | 8 + docs/start/framework/react/guide/seo.md | 283 +++++++++++++++++++++++ docs/start/framework/solid/guide/seo.md | 291 ++++++++++++++++++++++++ 3 files changed, 582 insertions(+) create mode 100644 docs/start/framework/react/guide/seo.md create mode 100644 docs/start/framework/solid/guide/seo.md diff --git a/docs/start/config.json b/docs/start/config.json index 2c65ff2027..0d67270608 100644 --- a/docs/start/config.json +++ b/docs/start/config.json @@ -73,6 +73,10 @@ "label": "Routing", "to": "framework/react/guide/routing" }, + { + "label": "SEO", + "to": "framework/react/guide/seo" + }, { "label": "Execution Model", "to": "framework/react/guide/execution-model" @@ -178,6 +182,10 @@ "label": "Routing", "to": "framework/solid/guide/routing" }, + { + "label": "SEO", + "to": "framework/solid/guide/seo" + }, { "label": "Execution Model", "to": "framework/solid/guide/execution-model" diff --git a/docs/start/framework/react/guide/seo.md b/docs/start/framework/react/guide/seo.md new file mode 100644 index 0000000000..c9031f7d70 --- /dev/null +++ b/docs/start/framework/react/guide/seo.md @@ -0,0 +1,283 @@ +--- +id: seo +title: SEO +--- + +## What is SEO, really? + +SEO (Search Engine Optimization) is often misunderstood as simply "showing up on Google" or a checkbox that a library can magically provide. In reality, SEO is a broad discipline focused on delivering valuable content that people need and making it easy for them to find. + +**Technical SEO** is a subset of SEO that developers interact with most directly. It involves using tools and APIs that satisfy the technical requirements of search engines, crawlers, rankers, and even LLMs. When someone says a framework has "good SEO support," they typically mean it provides the tools to make this process straightforward. + +TanStack Start provides comprehensive technical SEO capabilities, but you still need to put in the work to use them effectively. + +## What TanStack Start Provides + +TanStack Start gives you the building blocks for technical SEO: + +- **Server-Side Rendering (SSR)** - Ensures crawlers receive fully rendered HTML +- **Static Prerendering** - Pre-generates pages for optimal performance and crawlability +- **Document Head Management** - Full control over meta tags, titles, and structured data +- **Performance** - Fast load times through code-splitting, streaming, and optimal bundling + +## Document Head Management + +The `head` property on routes is your primary tool for SEO. It allows you to set page titles, meta descriptions, Open Graph tags, and more. + +### Basic Meta Tags + +```tsx +// src/routes/index.tsx +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/')({ + head: () => ({ + meta: [ + { title: 'My App - Home' }, + { + name: 'description', + content: 'Welcome to My App, a platform for...', + }, + ], + }), + component: HomePage, +}) +``` + +### Dynamic Meta Tags + +Use loader data to generate dynamic meta tags for content pages: + +```tsx +// src/routes/posts/$postId.tsx +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/posts/$postId')({ + loader: async ({ params }) => { + const post = await fetchPost(params.postId) + return { post } + }, + head: ({ loaderData }) => ({ + meta: [ + { title: loaderData.post.title }, + { name: 'description', content: loaderData.post.excerpt }, + ], + }), + component: PostPage, +}) +``` + +### Open Graph and Social Sharing + +Open Graph tags control how your pages appear when shared on social media: + +```tsx +export const Route = createFileRoute('/posts/$postId')({ + loader: async ({ params }) => { + const post = await fetchPost(params.postId) + return { post } + }, + head: ({ loaderData }) => ({ + meta: [ + { title: loaderData.post.title }, + { name: 'description', content: loaderData.post.excerpt }, + // Open Graph + { property: 'og:title', content: loaderData.post.title }, + { property: 'og:description', content: loaderData.post.excerpt }, + { property: 'og:image', content: loaderData.post.coverImage }, + { property: 'og:type', content: 'article' }, + // Twitter Card + { name: 'twitter:card', content: 'summary_large_image' }, + { name: 'twitter:title', content: loaderData.post.title }, + { name: 'twitter:description', content: loaderData.post.excerpt }, + { name: 'twitter:image', content: loaderData.post.coverImage }, + ], + }), + component: PostPage, +}) +``` + +### Canonical URLs + +Canonical URLs help prevent duplicate content issues: + +```tsx +export const Route = createFileRoute('/posts/$postId')({ + head: ({ params }) => ({ + links: [ + { + rel: 'canonical', + href: `https://myapp.com/posts/${params.postId}`, + }, + ], + }), + component: PostPage, +}) +``` + +## Structured Data (JSON-LD) + +Structured data helps search engines understand your content and can enable rich results in search: + +```tsx +export const Route = createFileRoute('/posts/$postId')({ + loader: async ({ params }) => { + const post = await fetchPost(params.postId) + return { post } + }, + head: ({ loaderData }) => ({ + meta: [{ title: loaderData.post.title }], + scripts: [ + { + type: 'application/ld+json', + children: JSON.stringify({ + '@context': 'https://schema.org', + '@type': 'Article', + headline: loaderData.post.title, + description: loaderData.post.excerpt, + image: loaderData.post.coverImage, + author: { + '@type': 'Person', + name: loaderData.post.author.name, + }, + datePublished: loaderData.post.publishedAt, + }), + }, + ], + }), + component: PostPage, +}) +``` + +## Server-Side Rendering + +SSR is enabled by default in TanStack Start. This ensures that search engine crawlers receive fully rendered HTML content, which is critical for SEO. + +```tsx +// SSR is automatic - your pages are rendered on the server +export const Route = createFileRoute('/about')({ + component: AboutPage, +}) +``` + +For routes that don't need SSR, you can disable it selectively. However, be aware this may impact SEO for those pages: + +```tsx +// Only disable SSR for pages that don't need SEO +export const Route = createFileRoute('/dashboard')({ + ssr: false, // Dashboard doesn't need to be indexed + component: DashboardPage, +}) +``` + +See the [Selective SSR guide](./selective-ssr) for more details. + +## Static Prerendering + +For content that doesn't change frequently, static prerendering generates HTML at build time for optimal performance: + +```ts +// vite.config.ts +import { tanstackStart } from '@tanstack/react-start/plugin/vite' + +export default defineConfig({ + plugins: [ + tanstackStart({ + prerender: { + enabled: true, + crawlLinks: true, + }, + }), + ], +}) +``` + +Prerendered pages load faster and are easily crawlable. See the [Static Prerendering guide](./static-prerendering) for configuration options. + +## Sitemaps and robots.txt + +You can create sitemaps and robots.txt files using [server routes](./server-routes): + +```tsx +// src/routes/sitemap.xml.ts +import { createServerFileRoute } from '@tanstack/react-start/server' + +export const ServerRoute = createServerFileRoute('/sitemap.xml')({ + GET: async () => { + const posts = await fetchAllPosts() + + const sitemap = ` + + + https://myapp.com/ + daily + 1.0 + + ${posts + .map( + (post) => ` + + https://myapp.com/posts/${post.id} + ${post.updatedAt} + weekly + `, + ) + .join('')} +` + + return new Response(sitemap, { + headers: { + 'Content-Type': 'application/xml', + }, + }) + }, +}) +``` + +```tsx +// src/routes/robots.txt.ts +import { createServerFileRoute } from '@tanstack/react-start/server' + +export const ServerRoute = createServerFileRoute('/robots.txt')({ + GET: async () => { + const robots = `User-agent: * +Allow: / + +Sitemap: https://myapp.com/sitemap.xml` + + return new Response(robots, { + headers: { + 'Content-Type': 'text/plain', + }, + }) + }, +}) +``` + +## Best Practices + +### Performance Matters + +Page speed is a ranking factor. TanStack Start helps with: + +- **Automatic code-splitting** - Only load the JavaScript needed for each page +- **Streaming SSR** - Start sending HTML to the browser immediately +- **Preloading** - Prefetch routes before users navigate to them + +### Content is King + +Technical SEO is just one piece of the puzzle. The most important factors are: + +- **Quality content** - Create content that provides value to users +- **Clear site structure** - Organize your routes logically +- **Descriptive URLs** - Use meaningful path segments (`/posts/my-great-article` vs `/posts/123`) +- **Internal linking** - Help users and crawlers discover your content + +### Test Your Implementation + +Use these tools to verify your SEO implementation: + +- [Google Search Console](https://search.google.com/search-console) - Monitor indexing and search performance +- [Google Rich Results Test](https://search.google.com/test/rich-results) - Validate structured data +- [Open Graph Debugger](https://developers.facebook.com/tools/debug/) - Preview social sharing cards +- Browser DevTools - Inspect rendered HTML and meta tags diff --git a/docs/start/framework/solid/guide/seo.md b/docs/start/framework/solid/guide/seo.md new file mode 100644 index 0000000000..bb7f2d2ee1 --- /dev/null +++ b/docs/start/framework/solid/guide/seo.md @@ -0,0 +1,291 @@ +--- +id: seo +title: SEO +--- + +## What is SEO, really? + +SEO (Search Engine Optimization) is often misunderstood as simply "showing up on Google" or a checkbox that a library can magically provide. In reality, SEO is a broad discipline focused on delivering valuable content that people need and making it easy for them to find. + +**Technical SEO** is a subset of SEO that developers interact with most directly. It involves using tools and APIs that satisfy the technical requirements of search engines, crawlers, rankers, and even LLMs. When someone says a framework has "good SEO support," they typically mean it provides the tools to make this process straightforward. + +TanStack Start provides comprehensive technical SEO capabilities, but you still need to put in the work to use them effectively. + +## What TanStack Start Provides + +TanStack Start gives you the building blocks for technical SEO: + +- **Server-Side Rendering (SSR)** - Ensures crawlers receive fully rendered HTML +- **Static Prerendering** - Pre-generates pages for optimal performance and crawlability +- **Document Head Management** - Full control over meta tags, titles, and structured data +- **Performance** - Fast load times through code-splitting, streaming, and optimal bundling + +## Document Head Management + +The `head` property on routes is your primary tool for SEO. It allows you to set page titles, meta descriptions, Open Graph tags, and more. + +### Basic Meta Tags + +```tsx +// src/routes/index.tsx +import { createFileRoute } from '@tanstack/solid-router' + +export const Route = createFileRoute('/')({ + head: () => ({ + meta: [ + { title: 'My App - Home' }, + { + name: 'description', + content: 'Welcome to My App, a platform for...', + }, + ], + }), + component: HomePage, +}) +``` + +### Dynamic Meta Tags + +Use loader data to generate dynamic meta tags for content pages: + +```tsx +// src/routes/posts/$postId.tsx +import { createFileRoute } from '@tanstack/solid-router' + +export const Route = createFileRoute('/posts/$postId')({ + loader: async ({ params }) => { + const post = await fetchPost(params.postId) + return { post } + }, + head: ({ loaderData }) => ({ + meta: [ + { title: loaderData.post.title }, + { name: 'description', content: loaderData.post.excerpt }, + ], + }), + component: PostPage, +}) +``` + +### Open Graph and Social Sharing + +Open Graph tags control how your pages appear when shared on social media: + +```tsx +export const Route = createFileRoute('/posts/$postId')({ + loader: async ({ params }) => { + const post = await fetchPost(params.postId) + return { post } + }, + head: ({ loaderData }) => ({ + meta: [ + { title: loaderData.post.title }, + { name: 'description', content: loaderData.post.excerpt }, + // Open Graph + { property: 'og:title', content: loaderData.post.title }, + { property: 'og:description', content: loaderData.post.excerpt }, + { property: 'og:image', content: loaderData.post.coverImage }, + { property: 'og:type', content: 'article' }, + // Twitter Card + { name: 'twitter:card', content: 'summary_large_image' }, + { name: 'twitter:title', content: loaderData.post.title }, + { name: 'twitter:description', content: loaderData.post.excerpt }, + { name: 'twitter:image', content: loaderData.post.coverImage }, + ], + }), + component: PostPage, +}) +``` + +### Canonical URLs + +Canonical URLs help prevent duplicate content issues: + +```tsx +export const Route = createFileRoute('/posts/$postId')({ + head: ({ params }) => ({ + links: [ + { + rel: 'canonical', + href: `https://myapp.com/posts/${params.postId}`, + }, + ], + }), + component: PostPage, +}) +``` + +## Structured Data (JSON-LD) + +Structured data helps search engines understand your content and can enable rich results in search: + +```tsx +export const Route = createFileRoute('/posts/$postId')({ + loader: async ({ params }) => { + const post = await fetchPost(params.postId) + return { post } + }, + head: ({ loaderData }) => ({ + meta: [{ title: loaderData.post.title }], + scripts: [ + { + type: 'application/ld+json', + children: JSON.stringify({ + '@context': 'https://schema.org', + '@type': 'Article', + headline: loaderData.post.title, + description: loaderData.post.excerpt, + image: loaderData.post.coverImage, + author: { + '@type': 'Person', + name: loaderData.post.author.name, + }, + datePublished: loaderData.post.publishedAt, + }), + }, + ], + }), + component: PostPage, +}) +``` + +## Server-Side Rendering + +SSR is enabled by default in TanStack Start. This ensures that search engine crawlers receive fully rendered HTML content, which is critical for SEO. + +```tsx +// SSR is automatic - your pages are rendered on the server +export const Route = createFileRoute('/about')({ + component: AboutPage, +}) +``` + +For routes that don't need SSR, you can disable it selectively. However, be aware this may impact SEO for those pages: + +```tsx +// Only disable SSR for pages that don't need SEO +export const Route = createFileRoute('/dashboard')({ + ssr: false, // Dashboard doesn't need to be indexed + component: DashboardPage, +}) +``` + +See the [Selective SSR guide](./selective-ssr) for more details. + +## Static Prerendering + +For content that doesn't change frequently, static prerendering generates HTML at build time for optimal performance: + +```ts +// vite.config.ts +import { tanstackStart } from '@tanstack/solid-start/plugin/vite' + +export default defineConfig({ + plugins: [ + tanstackStart({ + prerender: { + enabled: true, + crawlLinks: true, + }, + }), + ], +}) +``` + +Prerendered pages load faster and are easily crawlable. See the [Static Prerendering guide](./static-prerendering) for configuration options. + +## Sitemaps and robots.txt + +You can create sitemaps and robots.txt files using [server routes](./server-routes): + +```ts +// src/routes/sitemap.xml.ts +import { createFileRoute } from '@tanstack/solid-router' + +export const Route = createFileRoute('/sitemap.xml')({ + server: { + handlers: { + GET: async () => { + const posts = await fetchAllPosts() + + const sitemap = ` + + + https://myapp.com/ + daily + 1.0 + + ${posts + .map( + (post) => ` + + https://myapp.com/posts/${post.id} + ${post.updatedAt} + weekly + `, + ) + .join('')} +` + + return new Response(sitemap, { + headers: { + 'Content-Type': 'application/xml', + }, + }) + }, + }, + }, +}) +``` + +```ts +// src/routes/robots.txt.ts +import { createFileRoute } from '@tanstack/solid-router' + +export const Route = createFileRoute('/robots.txt')({ + server: { + handlers: { + GET: async () => { + const robots = `User-agent: * +Allow: / + +Sitemap: https://myapp.com/sitemap.xml` + + return new Response(robots, { + headers: { + 'Content-Type': 'text/plain', + }, + }) + }, + }, + }, +}) +``` + +## Best Practices + +### Performance Matters + +Page speed is a ranking factor. TanStack Start helps with: + +- **Automatic code-splitting** - Only load the JavaScript needed for each page +- **Streaming SSR** - Start sending HTML to the browser immediately +- **Preloading** - Prefetch routes before users navigate to them + +### Content is King + +Technical SEO is just one piece of the puzzle. The most important factors are: + +- **Quality content** - Create content that provides value to users +- **Clear site structure** - Organize your routes logically +- **Descriptive URLs** - Use meaningful path segments (`/posts/my-great-article` vs `/posts/123`) +- **Internal linking** - Help users and crawlers discover your content + +### Test Your Implementation + +Use these tools to verify your SEO implementation: + +- [Google Search Console](https://search.google.com/search-console) - Monitor indexing and search performance +- [Google Rich Results Test](https://search.google.com/test/rich-results) - Validate structured data +- [Open Graph Debugger](https://developers.facebook.com/tools/debug/) - Preview social sharing cards +- Browser DevTools - Inspect rendered HTML and meta tags From 6822df2c89b1210911f0b93100a51ec56445af99 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 24 Dec 2025 04:59:30 +0000 Subject: [PATCH 2/6] docs(start): add LLMO guide and cross-references with SEO guide Add a comprehensive LLM Optimization (LLMO) guide for both React and Solid frameworks, covering: - What LLMO/AIO/GEO is and how it differs from traditional SEO - Structured data (JSON-LD) for AI consumption - Schema.org examples: Article, Product, Organization, FAQ - Machine-readable API endpoints - Content best practices for AI extraction - llms.txt implementation - Monitoring AI citations Also adds cross-reference callouts between SEO and LLMO guides to help users discover related content. --- docs/start/config.json | 8 + docs/start/framework/react/guide/llmo.md | 355 ++++++++++++++++++++++ docs/start/framework/react/guide/seo.md | 3 + docs/start/framework/solid/guide/llmo.md | 363 +++++++++++++++++++++++ docs/start/framework/solid/guide/seo.md | 3 + 5 files changed, 732 insertions(+) create mode 100644 docs/start/framework/react/guide/llmo.md create mode 100644 docs/start/framework/solid/guide/llmo.md diff --git a/docs/start/config.json b/docs/start/config.json index 0d67270608..a75d9cb588 100644 --- a/docs/start/config.json +++ b/docs/start/config.json @@ -77,6 +77,10 @@ "label": "SEO", "to": "framework/react/guide/seo" }, + { + "label": "LLM Optimization (LLMO)", + "to": "framework/react/guide/llmo" + }, { "label": "Execution Model", "to": "framework/react/guide/execution-model" @@ -186,6 +190,10 @@ "label": "SEO", "to": "framework/solid/guide/seo" }, + { + "label": "LLM Optimization (LLMO)", + "to": "framework/solid/guide/llmo" + }, { "label": "Execution Model", "to": "framework/solid/guide/execution-model" diff --git a/docs/start/framework/react/guide/llmo.md b/docs/start/framework/react/guide/llmo.md new file mode 100644 index 0000000000..3b21e053e0 --- /dev/null +++ b/docs/start/framework/react/guide/llmo.md @@ -0,0 +1,355 @@ +--- +id: llmo +title: LLM Optimization (LLMO) +--- + +> [!NOTE] +> Looking for traditional search engine optimization? See the [SEO guide](./seo). + +## What is LLMO? + +**LLM Optimization (LLMO)**, also known as **AI Optimization (AIO)** or **Generative Engine Optimization (GEO)**, is the practice of structuring your content and data so that AI systems—like ChatGPT, Claude, Perplexity, and other LLM-powered tools—can accurately understand, cite, and recommend your content. + +While traditional SEO focuses on ranking in search engine results pages, LLMO focuses on being accurately represented in AI-generated responses. As more users get information through AI assistants rather than traditional search, this is becoming increasingly important. + +## How LLMO Differs from SEO + +| Aspect | SEO | LLMO | +|--------|-----|------| +| **Goal** | Rank in search results | Be cited/recommended by AI | +| **Audience** | Search engine crawlers | LLM training & retrieval systems | +| **Key signals** | Links, keywords, page speed | Structured data, clarity, authority | +| **Content format** | Optimized for snippets | Optimized for extraction & synthesis | + +The good news: many LLMO best practices overlap with SEO. Clear structure, authoritative content, and good metadata help both. + +## What TanStack Start Provides + +TanStack Start's features that support LLMO: + +- **Server-Side Rendering** - Ensures AI crawlers see fully rendered content +- **Structured Data** - JSON-LD support for machine-readable content +- **Document Head Management** - Meta tags that AI systems can parse +- **Server Routes** - Create machine-readable endpoints (APIs, feeds) + +## Structured Data for AI + +Structured data using schema.org vocabulary helps AI systems understand your content's meaning and context. This is perhaps the most important LLMO technique. + +### Article Schema + +```tsx +// src/routes/posts/$postId.tsx +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/posts/$postId')({ + loader: async ({ params }) => { + const post = await fetchPost(params.postId) + return { post } + }, + head: ({ loaderData }) => ({ + meta: [{ title: loaderData.post.title }], + scripts: [ + { + type: 'application/ld+json', + children: JSON.stringify({ + '@context': 'https://schema.org', + '@type': 'Article', + headline: loaderData.post.title, + description: loaderData.post.excerpt, + image: loaderData.post.coverImage, + author: { + '@type': 'Person', + name: loaderData.post.author.name, + url: loaderData.post.author.url, + }, + publisher: { + '@type': 'Organization', + name: 'My Company', + logo: { + '@type': 'ImageObject', + url: 'https://myapp.com/logo.png', + }, + }, + datePublished: loaderData.post.publishedAt, + dateModified: loaderData.post.updatedAt, + }), + }, + ], + }), + component: PostPage, +}) +``` + +### Product Schema + +For e-commerce, product schema helps AI assistants provide accurate product information: + +```tsx +export const Route = createFileRoute('/products/$productId')({ + loader: async ({ params }) => { + const product = await fetchProduct(params.productId) + return { product } + }, + head: ({ loaderData }) => ({ + meta: [{ title: loaderData.product.name }], + scripts: [ + { + type: 'application/ld+json', + children: JSON.stringify({ + '@context': 'https://schema.org', + '@type': 'Product', + name: loaderData.product.name, + description: loaderData.product.description, + image: loaderData.product.images, + brand: { + '@type': 'Brand', + name: loaderData.product.brand, + }, + offers: { + '@type': 'Offer', + price: loaderData.product.price, + priceCurrency: 'USD', + availability: loaderData.product.inStock + ? 'https://schema.org/InStock' + : 'https://schema.org/OutOfStock', + }, + aggregateRating: loaderData.product.rating + ? { + '@type': 'AggregateRating', + ratingValue: loaderData.product.rating, + reviewCount: loaderData.product.reviewCount, + } + : undefined, + }), + }, + ], + }), + component: ProductPage, +}) +``` + +### Organization and Website Schema + +Add organization schema to your root route for site-wide context: + +```tsx +// src/routes/__root.tsx +export const Route = createRootRoute({ + head: () => ({ + meta: [ + { charSet: 'utf-8' }, + { name: 'viewport', content: 'width=device-width, initial-scale=1' }, + ], + scripts: [ + { + type: 'application/ld+json', + children: JSON.stringify({ + '@context': 'https://schema.org', + '@type': 'WebSite', + name: 'My App', + url: 'https://myapp.com', + publisher: { + '@type': 'Organization', + name: 'My Company', + url: 'https://myapp.com', + logo: 'https://myapp.com/logo.png', + sameAs: [ + 'https://twitter.com/mycompany', + 'https://github.com/mycompany', + ], + }, + }), + }, + ], + }), + component: RootComponent, +}) +``` + +### FAQ Schema + +FAQ schema is particularly effective for LLMO—AI systems often extract Q&A pairs: + +```tsx +export const Route = createFileRoute('/faq')({ + loader: async () => { + const faqs = await fetchFAQs() + return { faqs } + }, + head: ({ loaderData }) => ({ + meta: [{ title: 'Frequently Asked Questions' }], + scripts: [ + { + type: 'application/ld+json', + children: JSON.stringify({ + '@context': 'https://schema.org', + '@type': 'FAQPage', + mainEntity: loaderData.faqs.map((faq) => ({ + '@type': 'Question', + name: faq.question, + acceptedAnswer: { + '@type': 'Answer', + text: faq.answer, + }, + })), + }), + }, + ], + }), + component: FAQPage, +}) +``` + +## Machine-Readable Endpoints + +Create API endpoints that AI systems and developers can consume directly: + +```tsx +// src/routes/api/products.ts +import { createServerFileRoute } from '@tanstack/react-start/server' + +export const ServerRoute = createServerFileRoute('/api/products')({ + GET: async ({ request }) => { + const url = new URL(request.url) + const category = url.searchParams.get('category') + + const products = await fetchProducts({ category }) + + return Response.json({ + '@context': 'https://schema.org', + '@type': 'ItemList', + itemListElement: products.map((product, index) => ({ + '@type': 'ListItem', + position: index + 1, + item: { + '@type': 'Product', + name: product.name, + description: product.description, + url: `https://myapp.com/products/${product.id}`, + }, + })), + }) + }, +}) +``` + +## Content Best Practices + +Beyond technical implementation, content structure matters for LLMO: + +### Clear, Factual Statements + +AI systems extract factual claims. Make your key information explicit: + +```tsx +// Good: Clear, extractable facts +function ProductDetails({ product }) { + return ( +
+

{product.name}

+

+ {product.name} is a {product.category} made by {product.brand}. + It costs ${product.price} and is available in {product.colors.join(', ')}. +

+
+ ) +} +``` + +### Hierarchical Structure + +Use proper heading hierarchy—AI systems use this to understand content organization: + +```tsx +function DocumentationPage() { + return ( +
+

Getting Started with TanStack Start

+ +
+

Installation

+

Install TanStack Start using npm...

+ +

Prerequisites

+

You'll need Node.js 18 or later...

+
+ +
+

Configuration

+

Configure your app in vite.config.ts...

+
+
+ ) +} +``` + +### Authoritative Attribution + +Include author information and sources—AI systems consider authority signals: + +```tsx +export const Route = createFileRoute('/posts/$postId')({ + head: ({ loaderData }) => ({ + meta: [ + { title: loaderData.post.title }, + { name: 'author', content: loaderData.post.author.name }, + { + property: 'article:author', + content: loaderData.post.author.profileUrl, + }, + { + property: 'article:published_time', + content: loaderData.post.publishedAt, + }, + ], + }), + component: PostPage, +}) +``` + +## llms.txt + +Some sites are adopting a `llms.txt` file (similar to `robots.txt`) to provide guidance to AI systems: + +```tsx +// src/routes/llms.txt.ts +import { createServerFileRoute } from '@tanstack/react-start/server' + +export const ServerRoute = createServerFileRoute('/llms.txt')({ + GET: async () => { + const content = `# My App + +> My App is a platform for building modern web applications. + +## Documentation +- Getting Started: https://myapp.com/docs/getting-started +- API Reference: https://myapp.com/docs/api + +## Key Facts +- Built with TanStack Start +- Supports React and Solid +- Full TypeScript support + +## Contact +- Website: https://myapp.com +- GitHub: https://github.com/mycompany/myapp +` + + return new Response(content, { + headers: { + 'Content-Type': 'text/plain', + }, + }) + }, +}) +``` + +## Monitoring AI Citations + +Unlike traditional SEO with established analytics, LLMO monitoring is still evolving. Consider: + +- **Test with AI assistants** - Ask ChatGPT, Claude, and Perplexity about your product/content +- **Monitor brand mentions** - Track how AI systems describe your offerings +- **Validate structured data** - Use [Google's Rich Results Test](https://search.google.com/test/rich-results) and [Schema.org Validator](https://validator.schema.org/) +- **Check AI search engines** - Monitor presence in Perplexity, Bing Chat, and Google AI Overviews diff --git a/docs/start/framework/react/guide/seo.md b/docs/start/framework/react/guide/seo.md index c9031f7d70..f7a4a0f8af 100644 --- a/docs/start/framework/react/guide/seo.md +++ b/docs/start/framework/react/guide/seo.md @@ -3,6 +3,9 @@ id: seo title: SEO --- +> [!NOTE] +> Looking to optimize for AI assistants and LLMs? See the [LLM Optimization (LLMO) guide](./llmo). + ## What is SEO, really? SEO (Search Engine Optimization) is often misunderstood as simply "showing up on Google" or a checkbox that a library can magically provide. In reality, SEO is a broad discipline focused on delivering valuable content that people need and making it easy for them to find. diff --git a/docs/start/framework/solid/guide/llmo.md b/docs/start/framework/solid/guide/llmo.md new file mode 100644 index 0000000000..f831521894 --- /dev/null +++ b/docs/start/framework/solid/guide/llmo.md @@ -0,0 +1,363 @@ +--- +id: llmo +title: LLM Optimization (LLMO) +--- + +> [!NOTE] +> Looking for traditional search engine optimization? See the [SEO guide](./seo). + +## What is LLMO? + +**LLM Optimization (LLMO)**, also known as **AI Optimization (AIO)** or **Generative Engine Optimization (GEO)**, is the practice of structuring your content and data so that AI systems—like ChatGPT, Claude, Perplexity, and other LLM-powered tools—can accurately understand, cite, and recommend your content. + +While traditional SEO focuses on ranking in search engine results pages, LLMO focuses on being accurately represented in AI-generated responses. As more users get information through AI assistants rather than traditional search, this is becoming increasingly important. + +## How LLMO Differs from SEO + +| Aspect | SEO | LLMO | +|--------|-----|------| +| **Goal** | Rank in search results | Be cited/recommended by AI | +| **Audience** | Search engine crawlers | LLM training & retrieval systems | +| **Key signals** | Links, keywords, page speed | Structured data, clarity, authority | +| **Content format** | Optimized for snippets | Optimized for extraction & synthesis | + +The good news: many LLMO best practices overlap with SEO. Clear structure, authoritative content, and good metadata help both. + +## What TanStack Start Provides + +TanStack Start's features that support LLMO: + +- **Server-Side Rendering** - Ensures AI crawlers see fully rendered content +- **Structured Data** - JSON-LD support for machine-readable content +- **Document Head Management** - Meta tags that AI systems can parse +- **Server Routes** - Create machine-readable endpoints (APIs, feeds) + +## Structured Data for AI + +Structured data using schema.org vocabulary helps AI systems understand your content's meaning and context. This is perhaps the most important LLMO technique. + +### Article Schema + +```tsx +// src/routes/posts/$postId.tsx +import { createFileRoute } from '@tanstack/solid-router' + +export const Route = createFileRoute('/posts/$postId')({ + loader: async ({ params }) => { + const post = await fetchPost(params.postId) + return { post } + }, + head: ({ loaderData }) => ({ + meta: [{ title: loaderData.post.title }], + scripts: [ + { + type: 'application/ld+json', + children: JSON.stringify({ + '@context': 'https://schema.org', + '@type': 'Article', + headline: loaderData.post.title, + description: loaderData.post.excerpt, + image: loaderData.post.coverImage, + author: { + '@type': 'Person', + name: loaderData.post.author.name, + url: loaderData.post.author.url, + }, + publisher: { + '@type': 'Organization', + name: 'My Company', + logo: { + '@type': 'ImageObject', + url: 'https://myapp.com/logo.png', + }, + }, + datePublished: loaderData.post.publishedAt, + dateModified: loaderData.post.updatedAt, + }), + }, + ], + }), + component: PostPage, +}) +``` + +### Product Schema + +For e-commerce, product schema helps AI assistants provide accurate product information: + +```tsx +export const Route = createFileRoute('/products/$productId')({ + loader: async ({ params }) => { + const product = await fetchProduct(params.productId) + return { product } + }, + head: ({ loaderData }) => ({ + meta: [{ title: loaderData.product.name }], + scripts: [ + { + type: 'application/ld+json', + children: JSON.stringify({ + '@context': 'https://schema.org', + '@type': 'Product', + name: loaderData.product.name, + description: loaderData.product.description, + image: loaderData.product.images, + brand: { + '@type': 'Brand', + name: loaderData.product.brand, + }, + offers: { + '@type': 'Offer', + price: loaderData.product.price, + priceCurrency: 'USD', + availability: loaderData.product.inStock + ? 'https://schema.org/InStock' + : 'https://schema.org/OutOfStock', + }, + aggregateRating: loaderData.product.rating + ? { + '@type': 'AggregateRating', + ratingValue: loaderData.product.rating, + reviewCount: loaderData.product.reviewCount, + } + : undefined, + }), + }, + ], + }), + component: ProductPage, +}) +``` + +### Organization and Website Schema + +Add organization schema to your root route for site-wide context: + +```tsx +// src/routes/__root.tsx +export const Route = createRootRoute({ + head: () => ({ + meta: [ + { charSet: 'utf-8' }, + { name: 'viewport', content: 'width=device-width, initial-scale=1' }, + ], + scripts: [ + { + type: 'application/ld+json', + children: JSON.stringify({ + '@context': 'https://schema.org', + '@type': 'WebSite', + name: 'My App', + url: 'https://myapp.com', + publisher: { + '@type': 'Organization', + name: 'My Company', + url: 'https://myapp.com', + logo: 'https://myapp.com/logo.png', + sameAs: [ + 'https://twitter.com/mycompany', + 'https://github.com/mycompany', + ], + }, + }), + }, + ], + }), + component: RootComponent, +}) +``` + +### FAQ Schema + +FAQ schema is particularly effective for LLMO—AI systems often extract Q&A pairs: + +```tsx +export const Route = createFileRoute('/faq')({ + loader: async () => { + const faqs = await fetchFAQs() + return { faqs } + }, + head: ({ loaderData }) => ({ + meta: [{ title: 'Frequently Asked Questions' }], + scripts: [ + { + type: 'application/ld+json', + children: JSON.stringify({ + '@context': 'https://schema.org', + '@type': 'FAQPage', + mainEntity: loaderData.faqs.map((faq) => ({ + '@type': 'Question', + name: faq.question, + acceptedAnswer: { + '@type': 'Answer', + text: faq.answer, + }, + })), + }), + }, + ], + }), + component: FAQPage, +}) +``` + +## Machine-Readable Endpoints + +Create API endpoints that AI systems and developers can consume directly: + +```ts +// src/routes/api/products.ts +import { createFileRoute } from '@tanstack/solid-router' + +export const Route = createFileRoute('/api/products')({ + server: { + handlers: { + GET: async ({ request }) => { + const url = new URL(request.url) + const category = url.searchParams.get('category') + + const products = await fetchProducts({ category }) + + return Response.json({ + '@context': 'https://schema.org', + '@type': 'ItemList', + itemListElement: products.map((product, index) => ({ + '@type': 'ListItem', + position: index + 1, + item: { + '@type': 'Product', + name: product.name, + description: product.description, + url: `https://myapp.com/products/${product.id}`, + }, + })), + }) + }, + }, + }, +}) +``` + +## Content Best Practices + +Beyond technical implementation, content structure matters for LLMO: + +### Clear, Factual Statements + +AI systems extract factual claims. Make your key information explicit: + +```tsx +// Good: Clear, extractable facts +function ProductDetails(props) { + return ( +
+

{props.product.name}

+

+ {props.product.name} is a {props.product.category} made by {props.product.brand}. + It costs ${props.product.price} and is available in {props.product.colors.join(', ')}. +

+
+ ) +} +``` + +### Hierarchical Structure + +Use proper heading hierarchy—AI systems use this to understand content organization: + +```tsx +function DocumentationPage() { + return ( +
+

Getting Started with TanStack Start

+ +
+

Installation

+

Install TanStack Start using npm...

+ +

Prerequisites

+

You'll need Node.js 18 or later...

+
+ +
+

Configuration

+

Configure your app in vite.config.ts...

+
+
+ ) +} +``` + +### Authoritative Attribution + +Include author information and sources—AI systems consider authority signals: + +```tsx +export const Route = createFileRoute('/posts/$postId')({ + head: ({ loaderData }) => ({ + meta: [ + { title: loaderData.post.title }, + { name: 'author', content: loaderData.post.author.name }, + { + property: 'article:author', + content: loaderData.post.author.profileUrl, + }, + { + property: 'article:published_time', + content: loaderData.post.publishedAt, + }, + ], + }), + component: PostPage, +}) +``` + +## llms.txt + +Some sites are adopting a `llms.txt` file (similar to `robots.txt`) to provide guidance to AI systems: + +```ts +// src/routes/llms.txt.ts +import { createFileRoute } from '@tanstack/solid-router' + +export const Route = createFileRoute('/llms.txt')({ + server: { + handlers: { + GET: async () => { + const content = `# My App + +> My App is a platform for building modern web applications. + +## Documentation +- Getting Started: https://myapp.com/docs/getting-started +- API Reference: https://myapp.com/docs/api + +## Key Facts +- Built with TanStack Start +- Supports React and Solid +- Full TypeScript support + +## Contact +- Website: https://myapp.com +- GitHub: https://github.com/mycompany/myapp +` + + return new Response(content, { + headers: { + 'Content-Type': 'text/plain', + }, + }) + }, + }, + }, +}) +``` + +## Monitoring AI Citations + +Unlike traditional SEO with established analytics, LLMO monitoring is still evolving. Consider: + +- **Test with AI assistants** - Ask ChatGPT, Claude, and Perplexity about your product/content +- **Monitor brand mentions** - Track how AI systems describe your offerings +- **Validate structured data** - Use [Google's Rich Results Test](https://search.google.com/test/rich-results) and [Schema.org Validator](https://validator.schema.org/) +- **Check AI search engines** - Monitor presence in Perplexity, Bing Chat, and Google AI Overviews diff --git a/docs/start/framework/solid/guide/seo.md b/docs/start/framework/solid/guide/seo.md index bb7f2d2ee1..f325ac1c64 100644 --- a/docs/start/framework/solid/guide/seo.md +++ b/docs/start/framework/solid/guide/seo.md @@ -3,6 +3,9 @@ id: seo title: SEO --- +> [!NOTE] +> Looking to optimize for AI assistants and LLMs? See the [LLM Optimization (LLMO) guide](./llmo). + ## What is SEO, really? SEO (Search Engine Optimization) is often misunderstood as simply "showing up on Google" or a checkbox that a library can magically provide. In reality, SEO is a broad discipline focused on delivering valuable content that people need and making it easy for them to find. From 1e8793cc9f4478b7466bf876c4a80f3d6e65c3e8 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Wed, 24 Dec 2025 05:01:57 +0000 Subject: [PATCH 3/6] ci: apply automated fixes --- docs/start/framework/react/guide/llmo.md | 16 ++++++++-------- docs/start/framework/solid/guide/llmo.md | 17 +++++++++-------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/docs/start/framework/react/guide/llmo.md b/docs/start/framework/react/guide/llmo.md index 3b21e053e0..561e83ec06 100644 --- a/docs/start/framework/react/guide/llmo.md +++ b/docs/start/framework/react/guide/llmo.md @@ -14,12 +14,12 @@ While traditional SEO focuses on ranking in search engine results pages, LLMO fo ## How LLMO Differs from SEO -| Aspect | SEO | LLMO | -|--------|-----|------| -| **Goal** | Rank in search results | Be cited/recommended by AI | -| **Audience** | Search engine crawlers | LLM training & retrieval systems | -| **Key signals** | Links, keywords, page speed | Structured data, clarity, authority | -| **Content format** | Optimized for snippets | Optimized for extraction & synthesis | +| Aspect | SEO | LLMO | +| ------------------ | --------------------------- | ------------------------------------ | +| **Goal** | Rank in search results | Be cited/recommended by AI | +| **Audience** | Search engine crawlers | LLM training & retrieval systems | +| **Key signals** | Links, keywords, page speed | Structured data, clarity, authority | +| **Content format** | Optimized for snippets | Optimized for extraction & synthesis | The good news: many LLMO best practices overlap with SEO. Clear structure, authoritative content, and good metadata help both. @@ -249,8 +249,8 @@ function ProductDetails({ product }) {

{product.name}

- {product.name} is a {product.category} made by {product.brand}. - It costs ${product.price} and is available in {product.colors.join(', ')}. + {product.name} is a {product.category} made by {product.brand}. It costs + ${product.price} and is available in {product.colors.join(', ')}.

) diff --git a/docs/start/framework/solid/guide/llmo.md b/docs/start/framework/solid/guide/llmo.md index f831521894..cd582faf4a 100644 --- a/docs/start/framework/solid/guide/llmo.md +++ b/docs/start/framework/solid/guide/llmo.md @@ -14,12 +14,12 @@ While traditional SEO focuses on ranking in search engine results pages, LLMO fo ## How LLMO Differs from SEO -| Aspect | SEO | LLMO | -|--------|-----|------| -| **Goal** | Rank in search results | Be cited/recommended by AI | -| **Audience** | Search engine crawlers | LLM training & retrieval systems | -| **Key signals** | Links, keywords, page speed | Structured data, clarity, authority | -| **Content format** | Optimized for snippets | Optimized for extraction & synthesis | +| Aspect | SEO | LLMO | +| ------------------ | --------------------------- | ------------------------------------ | +| **Goal** | Rank in search results | Be cited/recommended by AI | +| **Audience** | Search engine crawlers | LLM training & retrieval systems | +| **Key signals** | Links, keywords, page speed | Structured data, clarity, authority | +| **Content format** | Optimized for snippets | Optimized for extraction & synthesis | The good news: many LLMO best practices overlap with SEO. Clear structure, authoritative content, and good metadata help both. @@ -253,8 +253,9 @@ function ProductDetails(props) {

{props.product.name}

- {props.product.name} is a {props.product.category} made by {props.product.brand}. - It costs ${props.product.price} and is available in {props.product.colors.join(', ')}. + {props.product.name} is a {props.product.category} made by{' '} + {props.product.brand}. It costs ${props.product.price} and is available + in {props.product.colors.join(', ')}.

) From ba65e9b899ce88bf2ba948a312669789ded1d1bf Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 24 Dec 2025 05:01:57 +0000 Subject: [PATCH 4/6] docs(start): move SEO and LLMO guides to end of guides list --- docs/start/config.json | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/start/config.json b/docs/start/config.json index a75d9cb588..c5851d41e9 100644 --- a/docs/start/config.json +++ b/docs/start/config.json @@ -73,14 +73,6 @@ "label": "Routing", "to": "framework/react/guide/routing" }, - { - "label": "SEO", - "to": "framework/react/guide/seo" - }, - { - "label": "LLM Optimization (LLMO)", - "to": "framework/react/guide/llmo" - }, { "label": "Execution Model", "to": "framework/react/guide/execution-model" @@ -176,6 +168,14 @@ { "label": "Rendering Markdown", "to": "framework/react/guide/rendering-markdown" + }, + { + "label": "SEO", + "to": "framework/react/guide/seo" + }, + { + "label": "LLM Optimization (LLMO)", + "to": "framework/react/guide/llmo" } ] }, @@ -186,14 +186,6 @@ "label": "Routing", "to": "framework/solid/guide/routing" }, - { - "label": "SEO", - "to": "framework/solid/guide/seo" - }, - { - "label": "LLM Optimization (LLMO)", - "to": "framework/solid/guide/llmo" - }, { "label": "Execution Model", "to": "framework/solid/guide/execution-model" @@ -281,6 +273,14 @@ { "label": "Tailwind CSS Integration", "to": "framework/solid/guide/tailwind-integration" + }, + { + "label": "SEO", + "to": "framework/solid/guide/seo" + }, + { + "label": "LLM Optimization (LLMO)", + "to": "framework/solid/guide/llmo" } ] } From 43e6af1de2492a6ed56c7761a3b65d8886dd4c9f Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 24 Dec 2025 05:08:52 +0000 Subject: [PATCH 5/6] docs(start): fix server route examples to use createFileRoute Update SEO and LLMO guides to use createFileRoute with server.handlers instead of createServerFileRoute for consistency across React and Solid. --- docs/start/framework/react/guide/llmo.md | 74 +++++++++++++----------- docs/start/framework/react/guide/seo.md | 46 +++++++++------ 2 files changed, 68 insertions(+), 52 deletions(-) diff --git a/docs/start/framework/react/guide/llmo.md b/docs/start/framework/react/guide/llmo.md index 561e83ec06..a8fd49d019 100644 --- a/docs/start/framework/react/guide/llmo.md +++ b/docs/start/framework/react/guide/llmo.md @@ -205,31 +205,35 @@ export const Route = createFileRoute('/faq')({ Create API endpoints that AI systems and developers can consume directly: -```tsx +```ts // src/routes/api/products.ts -import { createServerFileRoute } from '@tanstack/react-start/server' - -export const ServerRoute = createServerFileRoute('/api/products')({ - GET: async ({ request }) => { - const url = new URL(request.url) - const category = url.searchParams.get('category') - - const products = await fetchProducts({ category }) - - return Response.json({ - '@context': 'https://schema.org', - '@type': 'ItemList', - itemListElement: products.map((product, index) => ({ - '@type': 'ListItem', - position: index + 1, - item: { - '@type': 'Product', - name: product.name, - description: product.description, - url: `https://myapp.com/products/${product.id}`, - }, - })), - }) +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/api/products')({ + server: { + handlers: { + GET: async ({ request }) => { + const url = new URL(request.url) + const category = url.searchParams.get('category') + + const products = await fetchProducts({ category }) + + return Response.json({ + '@context': 'https://schema.org', + '@type': 'ItemList', + itemListElement: products.map((product, index) => ({ + '@type': 'ListItem', + position: index + 1, + item: { + '@type': 'Product', + name: product.name, + description: product.description, + url: `https://myapp.com/products/${product.id}`, + }, + })), + }) + }, + }, }, }) ``` @@ -312,13 +316,15 @@ export const Route = createFileRoute('/posts/$postId')({ Some sites are adopting a `llms.txt` file (similar to `robots.txt`) to provide guidance to AI systems: -```tsx +```ts // src/routes/llms.txt.ts -import { createServerFileRoute } from '@tanstack/react-start/server' +import { createFileRoute } from '@tanstack/react-router' -export const ServerRoute = createServerFileRoute('/llms.txt')({ - GET: async () => { - const content = `# My App +export const Route = createFileRoute('/llms.txt')({ + server: { + handlers: { + GET: async () => { + const content = `# My App > My App is a platform for building modern web applications. @@ -336,11 +342,13 @@ export const ServerRoute = createServerFileRoute('/llms.txt')({ - GitHub: https://github.com/mycompany/myapp ` - return new Response(content, { - headers: { - 'Content-Type': 'text/plain', + return new Response(content, { + headers: { + 'Content-Type': 'text/plain', + }, + }) }, - }) + }, }, }) ``` diff --git a/docs/start/framework/react/guide/seo.md b/docs/start/framework/react/guide/seo.md index f7a4a0f8af..67f886d4c7 100644 --- a/docs/start/framework/react/guide/seo.md +++ b/docs/start/framework/react/guide/seo.md @@ -201,15 +201,17 @@ Prerendered pages load faster and are easily crawlable. See the [Static Prerende You can create sitemaps and robots.txt files using [server routes](./server-routes): -```tsx +```ts // src/routes/sitemap.xml.ts -import { createServerFileRoute } from '@tanstack/react-start/server' +import { createFileRoute } from '@tanstack/react-router' -export const ServerRoute = createServerFileRoute('/sitemap.xml')({ - GET: async () => { - const posts = await fetchAllPosts() +export const Route = createFileRoute('/sitemap.xml')({ + server: { + handlers: { + GET: async () => { + const posts = await fetchAllPosts() - const sitemap = ` + const sitemap = ` https://myapp.com/ @@ -228,31 +230,37 @@ export const ServerRoute = createServerFileRoute('/sitemap.xml')({ .join('')} ` - return new Response(sitemap, { - headers: { - 'Content-Type': 'application/xml', + return new Response(sitemap, { + headers: { + 'Content-Type': 'application/xml', + }, + }) }, - }) + }, }, }) ``` -```tsx +```ts // src/routes/robots.txt.ts -import { createServerFileRoute } from '@tanstack/react-start/server' +import { createFileRoute } from '@tanstack/react-router' -export const ServerRoute = createServerFileRoute('/robots.txt')({ - GET: async () => { - const robots = `User-agent: * +export const Route = createFileRoute('/robots.txt')({ + server: { + handlers: { + GET: async () => { + const robots = `User-agent: * Allow: / Sitemap: https://myapp.com/sitemap.xml` - return new Response(robots, { - headers: { - 'Content-Type': 'text/plain', + return new Response(robots, { + headers: { + 'Content-Type': 'text/plain', + }, + }) }, - }) + }, }, }) ``` From 7f1f93ba50670ff95e6ab10732397493dce23701 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 24 Dec 2025 05:14:40 +0000 Subject: [PATCH 6/6] docs(start): document built-in sitemap and fix route file naming - Add built-in sitemap generation with prerender + crawlLinks - Show dynamic sitemap as alternative for dynamic content - Fix escaped period syntax in file names: sitemap[.]xml.ts, robots[.]txt.ts, llms[.]txt.ts - Add CDN caching recommendation for dynamic sitemaps --- docs/start/framework/react/guide/llmo.md | 2 +- docs/start/framework/react/guide/seo.md | 40 +++++++++++++++++++++--- docs/start/framework/solid/guide/llmo.md | 2 +- docs/start/framework/solid/guide/seo.md | 40 +++++++++++++++++++++--- 4 files changed, 74 insertions(+), 10 deletions(-) diff --git a/docs/start/framework/react/guide/llmo.md b/docs/start/framework/react/guide/llmo.md index a8fd49d019..25007890fa 100644 --- a/docs/start/framework/react/guide/llmo.md +++ b/docs/start/framework/react/guide/llmo.md @@ -317,7 +317,7 @@ export const Route = createFileRoute('/posts/$postId')({ Some sites are adopting a `llms.txt` file (similar to `robots.txt`) to provide guidance to AI systems: ```ts -// src/routes/llms.txt.ts +// src/routes/llms[.]txt.ts import { createFileRoute } from '@tanstack/react-router' export const Route = createFileRoute('/llms.txt')({ diff --git a/docs/start/framework/react/guide/seo.md b/docs/start/framework/react/guide/seo.md index 67f886d4c7..f05fc63755 100644 --- a/docs/start/framework/react/guide/seo.md +++ b/docs/start/framework/react/guide/seo.md @@ -197,12 +197,40 @@ export default defineConfig({ Prerendered pages load faster and are easily crawlable. See the [Static Prerendering guide](./static-prerendering) for configuration options. -## Sitemaps and robots.txt +## Sitemaps -You can create sitemaps and robots.txt files using [server routes](./server-routes): +### Built-in Sitemap Generation + +TanStack Start can automatically generate a sitemap when you enable prerendering with link crawling: ```ts -// src/routes/sitemap.xml.ts +// vite.config.ts +import { tanstackStart } from '@tanstack/react-start/plugin/vite' + +export default defineConfig({ + plugins: [ + tanstackStart({ + prerender: { + enabled: true, + crawlLinks: true, // Discovers all linkable pages + }, + sitemap: { + enabled: true, + host: 'https://myapp.com', + }, + }), + ], +}) +``` + +The sitemap is generated at build time by crawling all discoverable pages from your routes. This is the recommended approach for static or mostly-static sites. + +### Dynamic Sitemap + +For sites with dynamic content that can't be discovered at build time, you can create a dynamic sitemap using a [server route](./server-routes). Consider caching this at your CDN for performance: + +```ts +// src/routes/sitemap[.]xml.ts import { createFileRoute } from '@tanstack/react-router' export const Route = createFileRoute('/sitemap.xml')({ @@ -241,8 +269,12 @@ export const Route = createFileRoute('/sitemap.xml')({ }) ``` +## robots.txt + +You can create a robots.txt file using a [server route](./server-routes): + ```ts -// src/routes/robots.txt.ts +// src/routes/robots[.]txt.ts import { createFileRoute } from '@tanstack/react-router' export const Route = createFileRoute('/robots.txt')({ diff --git a/docs/start/framework/solid/guide/llmo.md b/docs/start/framework/solid/guide/llmo.md index cd582faf4a..770f32e8d7 100644 --- a/docs/start/framework/solid/guide/llmo.md +++ b/docs/start/framework/solid/guide/llmo.md @@ -318,7 +318,7 @@ export const Route = createFileRoute('/posts/$postId')({ Some sites are adopting a `llms.txt` file (similar to `robots.txt`) to provide guidance to AI systems: ```ts -// src/routes/llms.txt.ts +// src/routes/llms[.]txt.ts import { createFileRoute } from '@tanstack/solid-router' export const Route = createFileRoute('/llms.txt')({ diff --git a/docs/start/framework/solid/guide/seo.md b/docs/start/framework/solid/guide/seo.md index f325ac1c64..0e9a49edbd 100644 --- a/docs/start/framework/solid/guide/seo.md +++ b/docs/start/framework/solid/guide/seo.md @@ -197,12 +197,40 @@ export default defineConfig({ Prerendered pages load faster and are easily crawlable. See the [Static Prerendering guide](./static-prerendering) for configuration options. -## Sitemaps and robots.txt +## Sitemaps -You can create sitemaps and robots.txt files using [server routes](./server-routes): +### Built-in Sitemap Generation + +TanStack Start can automatically generate a sitemap when you enable prerendering with link crawling: ```ts -// src/routes/sitemap.xml.ts +// vite.config.ts +import { tanstackStart } from '@tanstack/solid-start/plugin/vite' + +export default defineConfig({ + plugins: [ + tanstackStart({ + prerender: { + enabled: true, + crawlLinks: true, // Discovers all linkable pages + }, + sitemap: { + enabled: true, + host: 'https://myapp.com', + }, + }), + ], +}) +``` + +The sitemap is generated at build time by crawling all discoverable pages from your routes. This is the recommended approach for static or mostly-static sites. + +### Dynamic Sitemap + +For sites with dynamic content that can't be discovered at build time, you can create a dynamic sitemap using a [server route](./server-routes). Consider caching this at your CDN for performance: + +```ts +// src/routes/sitemap[.]xml.ts import { createFileRoute } from '@tanstack/solid-router' export const Route = createFileRoute('/sitemap.xml')({ @@ -241,8 +269,12 @@ export const Route = createFileRoute('/sitemap.xml')({ }) ``` +## robots.txt + +You can create a robots.txt file using a [server route](./server-routes): + ```ts -// src/routes/robots.txt.ts +// src/routes/robots[.]txt.ts import { createFileRoute } from '@tanstack/solid-router' export const Route = createFileRoute('/robots.txt')({