TanStack Start Open Graph Meta Tags: Server-Side OG in TanStack Router

How to add og:title, og:image, og:description, and Twitter card meta tags in TanStack Start using createFileRoute, useHead, and server-side loader functions.

Why TanStack Start enables real server-side OG

TanStack Start is a full-stack React framework built on TanStack Router. Unlike traditional React SPAs, TanStack Start performs server-side rendering (SSR) by default — your routes are rendered on the server and the full HTML (including <head> tags) is sent to the browser.

Social crawlers (Twitterbot, LinkedInBot, Discordbot) parse raw HTML without executing JavaScript. Because TanStack Start renders on the server, your OG tags are embedded in the initial HTML response — exactly what crawlers need.

The key APIs are createFileRoute for type-safe file-based routing, useHead (from @tanstack/react-router) for per-route head management, and server functions / loaders for fetching dynamic data.

createFileRoute + useHead for static OG

For pages with known, static content, use createFileRoute and set head tags in the route component using useHead:

// src/routes/index.tsx
import { createFileRoute } from '@tanstack/react-router';
import { useHead } from '@tanstack/react-router';

export const Route = createFileRoute('/')({
  component: HomePage,
});

function HomePage() {
  useHead({
    title: 'My TanStack App — Build Faster',
    meta: [
      { name: 'description',         content: 'A full-stack React app with TanStack Start.' },
      { property: 'og:type',         content: 'website' },
      { property: 'og:title',        content: 'My TanStack App — Build Faster' },
      { property: 'og:description',  content: 'A full-stack React app with TanStack Start.' },
      { property: 'og:image',        content: 'https://yourdomain.com/og/home.png' },
      { property: 'og:url',          content: 'https://yourdomain.com/' },
      { name: 'twitter:card',        content: 'summary_large_image' },
      { name: 'twitter:title',       content: 'My TanStack App — Build Faster' },
      { name: 'twitter:description', content: 'A full-stack React app with TanStack Start.' },
      { name: 'twitter:image',       content: 'https://yourdomain.com/og/home.png' },
    ],
  });

  return (
    <main>
      <h1>Welcome to My TanStack App</h1>
    </main>
  );
}

Loader data → dynamic OG tags

For dynamic routes like blog posts or product pages, fetch data in the route's loader function and use it to populate OG tags. The loader runs on the server, so OG tags are embedded in the SSR output.

// src/routes/blog/$slug.tsx
import { createFileRoute } from '@tanstack/react-router';
import { useHead } from '@tanstack/react-router';

export const Route = createFileRoute('/blog/$slug')({
  // Runs on the server — fetches post data before SSR
  loader: async ({ params }) => {
    const post = await fetchPost(params.slug);
    return { post };
  },
  component: BlogPostPage,
});

function BlogPostPage() {
  const { post } = Route.useLoaderData();

  useHead({
    title: `${post.title} | My Blog`,
    meta: [
      { name: 'description',          content: post.excerpt },
      { property: 'og:type',          content: 'article' },
      { property: 'og:title',         content: post.title },
      { property: 'og:description',   content: post.excerpt },
      { property: 'og:image',         content: post.ogImage },
      { property: 'og:url',           content: `https://yourdomain.com/blog/${post.slug}` },
      { property: 'article:published_time', content: post.publishedAt },
      { name: 'twitter:card',         content: 'summary_large_image' },
      { name: 'twitter:title',        content: post.title },
      { name: 'twitter:description',  content: post.excerpt },
      { name: 'twitter:image',        content: post.ogImage },
    ],
  });

  return (
    <article>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </article>
  );
}

Because the loader executes server-side, the post data (and therefore the OG tags) are available when TanStack Start renders the HTML response. Crawlers receive a fully populated <head>.

Dynamic og:image generation

TanStack Start server functions can generate dynamic OG images on the fly. Create a server route that renders an image using Satori or @vercel/og, then reference it in your OG tags:

// src/routes/api/og.tsx
// Server route that generates OG images
import { createAPIFileRoute } from '@tanstack/react-start/api';
import satori from 'satori';
import sharp from 'sharp';

export const APIRoute = createAPIFileRoute('/api/og')({
  GET: async ({ request }) => {
    const url = new URL(request.url);
    const title = url.searchParams.get('title') ?? 'My App';

    const svg = await satori(
      <div style={{ display: 'flex', background: '#000', width: 1200, height: 630 }}>
        <h1 style={{ color: '#fff', fontSize: 60 }}>{title}</h1>
      </div>,
      { width: 1200, height: 630, fonts: [] }
    );

    const png = await sharp(Buffer.from(svg)).png().toBuffer();
    return new Response(png, { headers: { 'Content-Type': 'image/png' } });
  },
});

// In your route component, reference the dynamic OG image:
// og:image = `https://yourdomain.com/api/og?title=${encodeURIComponent(post.title)}`

OG tag checklist for TanStack Start

  • Use useHead() in every route component to set page-specific OG tags.
  • For dynamic routes, fetch data in the route loader (runs server-side).
  • Set og:title, og:description, og:image, og:url, and og:type.
  • Add twitter:card as summary_large_image.
  • Use absolute URLs for og:image (1200×630 px).
  • Test after each deployment with OGFixer.

Test your TanStack Start OG tags

Paste any TanStack Start URL into OGFixer to preview how your links look on Twitter, LinkedIn, Discord, and Slack.

Related Guides