TanStack Start uses Nitro to execute the full React 19 component tree on the server before a single byte of HTML reaches the browser. Search engines index a complete, data-populated page on first crawl. Social network crawlers receive Open Graph and Twitter Card metadata with the correct title, description, and avatar image. No client-side JavaScript execution is required for any of this — the rendered HTML is the source of truth.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/santiagonieto09/portafolio/llms.txt
Use this file to discover all available pages before exploring further.
Head metadata
Thehead() export in src/routes/index.tsx is evaluated on the server during SSR and injects all metadata into <head> before the response is sent.
Title and description
Open Graph
| Property | Value |
|---|---|
og:title | Page title |
og:description | Page description |
og:type | profile |
og:url | / |
og:image | GitHub avatar URL (https://avatars.githubusercontent.com/u/91501165?v=4) |
Twitter Card
| Name | Value |
|---|---|
twitter:card | summary_large_image |
twitter:title | Page title |
twitter:description | Page description |
twitter:image | GitHub avatar URL |
Canonical link
JSON-LD structured data
A<script type="application/ld+json"> block is injected with a Person entity:
Sitemap
src/routes/sitemap[.]xml.ts handles GET /sitemap.xml as a server-side route handler. On each request it:
- Reads the
SITE_URLenvironment variable. If set, that value is used as the canonical base URL (trailing slashes stripped). If not set, the base URL is derived fromnew URL(request.url).origin— so the sitemap is always self-consistent regardless of which domain it is served from. - Builds a
<url>entry for/with<changefreq>weekly</changefreq>and<priority>1.0</priority>. - Returns the XML document with
Content-Type: application/xmlandCache-Control: public, max-age=3600.
/sitemap.xml to Google Search Console and Bing Webmaster Tools after the first deploy.
Data loader
Theloader in src/routes/index.tsx pre-populates the React Query cache on the server so components render with full data immediately:
ensureQueryData checks whether the ['portfolio'] query is already in the cache. On first render (SSR) it is not, so it calls getPortfolio() — a TanStack Start server function that executes in-process, not over HTTP — and stores the result. On subsequent renders within the same server process (if the QueryClient is reused), it returns the cached value immediately.
The staleTime: 1000 * 60 * 60 option (1 hour) in portfolioQueryOptions() means the client will not trigger a background refetch for 60 minutes after hydration, even though ensureQueryData considers data “available” the moment it exists in the cache.
React Query integration
portfolioQueryOptions() in src/lib/portfolio.queries.ts centralises the query configuration used by both the loader and the component:
| Option | Value | Purpose |
|---|---|---|
queryKey | ['portfolio'] | Unique cache key; used for invalidation and dehydration. |
queryFn | () => getPortfolio() | Calls the TanStack Start server function. |
staleTime | 1000 * 60 * 60 (1 h) | Client-side freshness window; prevents unnecessary refetches. |
gcTime | 1000 * 60 * 60 * 24 (24 h) | How long unused cache entries are kept in memory before garbage collection. |
portfolioQueryOptions() object is passed to both context.queryClient.ensureQueryData() in the loader and useSuspenseQuery() in the component, guaranteeing they reference the same cache key and configuration.
TanStack Start uses
useSuspenseQuery on the portfolio page. Because the loader calls ensureQueryData before React begins rendering, the query cache already contains the snapshot when the component tree runs — both on the server and after hydration on the client. The Suspense boundary is never in a pending state during SSR, so the page always streams fully rendered HTML with no loading skeleton or fallback content visible to crawlers or users.