TanStack Start
-
Install the package:
Terminal window npm install aeo.js -
Add a post-build step to your
package.json:{"scripts": {"postbuild": "node -e \"import('aeo.js/tanstack-start').then(m => m.postBuild({ title: 'My Site', url: 'https://mysite.com' }))\""}} -
Build your app:
Terminal window npm run build
How it works
Section titled “How it works”The TanStack Start plugin:
- Scans
src/routes(falling back toapp/routes) using the TanStack Router file conventions: flat (.) and directory nesting,indextokens,route.tsxlayout tokens, pathless_layoutsegments, and trailing-underscore un-nesting - Skips routes that can’t be enumerated statically — dynamic params (
$postId), splats ($), the__rootlayout, and-prefixed files - Scans prerendered HTML from the build output (
.output/public,dist/client, ordist) for titles, descriptions, and full text content - Generates all AEO files (robots.txt, llms.txt, sitemap.xml, ai-index.json, …) alongside the static assets so they’re served from the site root
Widget
Section titled “Widget”TanStack Start renders HTML on the server, so add the widget script once in your root document (src/routes/__root.tsx):
import { getWidgetScript } from 'aeo.js/tanstack-start';
const widgetScript = getWidgetScript({ title: 'My Site', url: 'https://mysite.com',});
// In your root document body, before </body>:<div dangerouslySetInnerHTML={{ __html: widgetScript }} />Programmatic usage
Section titled “Programmatic usage”No build output yet? Generate AEO files from source routes only — files land in public/:
import { generate } from 'aeo.js/tanstack-start';
await generate({ title: 'My Site', url: 'https://mysite.com' });Configuration
Section titled “Configuration”Pass any AeoConfig options to postBuild or generate:
import { postBuild } from 'aeo.js/tanstack-start';
await postBuild({ title: 'My Site', url: 'https://mysite.com', description: 'A site optimized for AI discovery', schema: { organization: { name: 'My Company' } },});