Přeskočit na obsah
BHPS, úvodní stránka

Zápisky

TanStack Start 1.0 je venku: proč na něm stavíme a proč jsem opustil Next.js

Jan Szotkowski

V tomhle článku

TanStack Start 1.0 je oficiálně stabilní. Tanner Linsley to ohlásil 13. října 2026 na blogu TanStacku a já na to čekal dlouho. Ne proto, že bych do té doby Start nepoužíval. Používal. Čekal jsem, až budu moct klientům, kolegům a každému, kdo se zeptá, říct: je to hotové, je to stabilní, klidně na tom stavte.

Ptají se mě na to často. „Jakou frontendovou technologii bys dnes zvolil na nový projekt?" Moje odpověď je už nějakou dobu stejná: TanStack Start, a k němu zbytek TanStacku. Je to první věc, po které sáhnu, když zakládám nový projekt. A momentálně nemám jediný důvod to měnit.

V tomhle článku shrnu, co verze 1.0 znamená, co k tomu píše sám Tanner, a hlavně ukážu, jak Start používáme v produkci na dvou projektech, na tomhle webu bhpslabs.com a na aplikaci udalist.app. Bez teorie, na skutečném kódu.

Co znamená „1.0"

Start běží v produkci u spousty firem už dlouho. Od malých projektů po enterprise týmy, a jak Tanner sám přiznává, řada z nich ho nasadila ještě v betě, i když jim to tým rozmlouval. My jsme na tom byli stejně.

Verze 1.0 proto není o tom, že by Start najednou začal fungovat. Je to formální závazek k API. Můžete si Start vybrat, naučit se ho, postavit na něm produkt a nemusíte se bát, že vám za půl roku překope celý způsob, jakým aplikace funguje. Pro firmu, která na technologii sází peníze a lidi, je tohle ta nejdůležitější vlastnost ze všech.

Tanner taky otevřeně píše, že cesta od release candidate k 1.0 trvala déle, než čekal. Mezitím do frameworku přibyla práce na kompilátoru, streamingu, hydrataci a hranicích mezi serverem a klientem. Manuel Schiller a Florian Pellet se zaměřili na výkon SSR a v jejich benchmarku dostali zhruba 5,5× vyšší propustnost. Christopher Horobin stojí za tím, že extrémně silné typy routeru nezaseknou editor. To jsou věci, které v changelogu nevypadají dramaticky, ale v produkci je poznáte.

Co Tanner v článku říká (a proč s ním souhlasím)

Celý článek doporučuju přečíst v originále. Pro ty, kdo nemají čas, tady jsou body, které mi mluví z duše.

Všechno začalo routerem

Start nevznikl jako framework. Vznikl jako router, u kterého Tanner chtěl, aby věděl všechno: jaké cesty existují, jaké parametry potřebují, jaké query parametry jsou platné, co vrací loader a jaký kontext je kde dostupný. A aby vám editor při každé změně řekl, co dalšího se musí upravit.

Před pár lety tomu spousta lidí nevěřila. Dnes je to podle mě největší důvod, proč TanStack Router a Start používat.

Jiná cesta než „všechno na serveru"

Tanner popisuje, že React ekosystém se v posledních letech hodně zúžil na jednu představu o tom, jak má aplikace vypadat. Next.js vsadil na React Server Components jako základ frameworku i jako ideologii. Start jde jinudy: aplikace zůstane aplikací, se stavem, klientskou navigací a cachováním dat. Server rendering, streaming a server funkce přidáte tam, kde dávají smysl, ale nemusíte kvůli nim přepisovat celé uvažování o aplikaci.

Každá route si může vybrat, jestli se vykreslí na serveru, jestli na serveru jen načte data, nebo jestli poběží čistě na klientu. Server funkce jsou typované a volají se z loaderu i z event handleru. Middleware umí běžet na klientu i na serveru a typy kontextu jdou skrz.

RSC jako volba, ne povinnost

Zajímavá pasáž je o React Server Components. Tým na nich strávil hodně času a Start je podporuje, ale tak, aby nepřevzaly kontrolu nad celou aplikací. A pointa: na tanstack.com je nakonec vypnuli, protože bylo čím dál těžší uvažovat o tom, co se kam posílá, a to platilo pro lidi i pro AI modely. Vypnutí přitom neznamenalo přepisovat aplikaci. To je přesně ten druh svobody, který od frameworku chci.

Hosting kdekoli

Start stojí na Vite a Nitru (a nově umí i Rsbuild), takže nasazení není svázané s jedním poskytovatelem. Netlify, Vercel, Cloudflare, Railway, Render, nebo vlastní Docker kontejner s Node serverem, jak to děláme my.

Typy pomáhají i AI agentům

Tohle považuju za nejvíc podceňovaný argument. Striktní typy a explicitní API vznikly pro lidi, ale AI agentům pomáhají úplně stejně. Když agent změní parametr route nebo vstup server funkce, TypeScript mu hned ukáže všechna místa, která s tou změnou nesouhlasí. TanStack navíc začal přidávat do npm balíčků takzvané skills (přes TanStack Intent), takže agent nemusí spoléhat na zastaralá trénovací data, ale čte aktuální doporučené postupy přímo z balíčku.

Proč jsem opustil Next.js

Next.js jsem používal dlouho a nechci ho shazovat. Umí skvěle vysvětlit a prodat svou myšlenku a spoustu lidí to naučil. Jenže čím dál víc jsem měl pocit, že bojuju s frameworkem místo toho, abych stavěl produkt.

  • "use client" a "use server" direktivy rozhodují o tom, kde kód běží, a hranice nejsou vždycky vidět.
  • Cachování se v několika verzích za sebou změnilo od základu a bylo těžké odhadnout, co je cachované, kde a jak dlouho.
  • Mentální model App Routeru je pro juniora (a upřímně i pro seniora) těžký: serverové komponenty, klientské komponenty, co smí importovat co.
  • Typová bezpečnost routování je spíš doplněk než základ. Query parametry jsou v podstatě string | string[] | undefined.

U Startu je to opačně. Komponenty jsou komponenty, routy jsou routy, a když potřebuju server, napíšu to explicitně. Nemusím mít v hlavě druhý model aplikace, abych prošel běžným dnem.

S Tannerem jsem se potkal i osobně v Amsterdamu a ten rozhovor mi potvrdil, co jsem z kódu cítil dávno: za TanStackem je člověk, kterému jde o to, aby se nástroje dobře používaly, ne o to, aby se dobře prodávaly.

Developer experience a učící křivka

DX je u Startu podle mě o třídu dál a nejlépe to ukáže pár konkrétních věcí.

Typované routy bez generování v hlavě. Router si sám generuje strom rout (routeTree.gen.ts). Odkaz na neexistující stránku nebo chybějící parametr je chyba při kompilaci, ne 404 v produkci. Na udalist.app máme přes 80 <Link> komponent a každá z nich je typově zkontrolovaná.

Query parametry jako typovaný stav. validateSearch (na Udalistu ho používá sedm rout) udělá z query parametrů validovaný a typovaný objekt. Filtry, stránkování nebo stav formuláře v URL přestanou být zdrojem chyb.

Explicitní server. Server funkce je obyčejná funkce, kterou zavoláte. Vidíte, co jde dovnitř, co jde ven a že běží na serveru. Žádná magie.

Učící křivka. Kdo zná React a umí trochu TypeScript, je ve Startu produktivní za pár dní. Nemusí se učit nový paradigma, jen router. A kdo zná TanStack Query, je doma ještě rychleji. U Next.js App Routeru jsem viděl zkušené vývojáře tápat týdny.

SEO a GEO: tady Start opravdu vyniká

O SEO a GEO (Generative Engine Optimization, tedy optimalizaci pro AI asistenty typu ChatGPT, Claude nebo Perplexity) jsme na tomhle webu strávili hodně času. A Start nám v tom nestál v cestě ani jednou. Naopak.

Metadata u každé route

Každá route má funkci head(), která vrací titulek, popis, canonical, hreflang, Open Graph i JSON-LD. Je typovaná, zná parametry route a běží při SSR, takže crawler dostane hotové HTML. Takhle zjednodušeně vypadá route tohoto článku:

export const Route = createFileRoute('/$locale/blog/$slug')({
    beforeLoad: ({ params }) => {
        if (!findPost(posts, params.locale, params.slug)) throw notFound();
    },
    head: ({ params }) => {
        const post = findPost(posts, params.locale, params.slug);
        return pageHead({
            title: post.title,
            description: post.description,
            ogType: 'article',
            alternates, // hreflang na překlad článku
            nodes: [blogPostingNode({ headline: post.title /* … */ })], // JSON-LD
        });
    },
    component: ArticlePage,
});

Všimněte si i beforeLoad. Starý tvar adresy přesměruje trvalým 301 a neexistující článek vrátí skutečnou 404, ne prázdnou stránku se stavovým kódem 200. Na tom SEO hodně záleží.

Prerender a sitemap přímo v konfiguraci

Statické stránky necháváme předgenerovat při buildu a sitemap vzniká automaticky. Na obou projektech je to pár řádků ve vite.config.ts:

tanstackStart({
    pages: getTanstackStartPages(),
    prerender: { enabled: true, crawlLinks: false, autoStaticPathsDiscovery: false },
    sitemap: { enabled: true, host: 'https://bhpslabs.com/' },
}),

Na Udalistu má prerender navíc filtr, který vynechá přihlášenou část aplikace (dashboard, autentizaci). Marketingové stránky jsou tak statické a bleskové, aplikace za přihlášením běží jako klasická SPA.

Web, kterému rozumí i AI

Tady se ukazuje síla toho, že Start nic neschovává. Vlastní serverový vstup (src/server.ts) je obyčejný fetch handler, do kterého si můžete přidat cokoli. Na bhpslabs.com díky tomu:

  • vracíme stejnou stránku jako Markdown, když si o to AI agent řekne hlavičkou Accept: text/markdown. Agent nemusí parsovat HTML a dostane čistý text,
  • skládáme Content-Security-Policy pro každou odpověď zvlášť z otisků inline skriptů, bez unsafe-inline,
  • servírujeme soubory pod /.well-known/ pro objevování agenty (katalog, agent skills),
  • k tomu robots.txt s pravidly pro AI crawlery a llms.txt, který modelům říká, co děláme a kdy nás doporučit.
export default {
    async fetch(request: Request) {
        const wellKnown = await wellKnownResponse(request);
        if (wellKnown) return wellKnown;

        const markdown = wantsMarkdown(request.headers.get('accept'));
        const response = await paraglideMiddleware(request, () => handler.fetch(request));

        if (markdown) return toMarkdownResponse(response);
        // … CSP z otisků inline skriptů, Vary, gzip
        return response;
    },
};

Udalist má velmi podobný vstup: Paraglide middleware, bezpečnostní hlavičky, Markdown pro úvodní stránku a /.well-known/ soubory. Jednou vymyšlené, dvakrát použité.

Naše projekty v produkci

bhpslabs.com

Tenhle web běží na TanStack Startu, TanStack Routeru, Reactu 19, Vite a Nitru, nasazený jako Node server v Dockeru. Je dvojjazyčný (čeština a angličtina) přes Paraglide a cesty mají tvar /$locale/....

Pár věcí, které stojí za zmínku:

  • Blog (ano, i tenhle článek) se načítá z Markdown souborů přes vlastní Vite plugin, který je při buildu zvaliduje a převede do typovaných dat. Překlady článků spojuje složka, ne adresa.
  • Poptávkový formulář odesílá data přes typovanou server funkci s validací a rate limitem:
export const sendAuditRequest = createServerFn({ method: 'POST' })
    .validator((value: unknown): SendInput => {
        if (!isInput(value)) throw new Error('Invalid input');
        return value;
    })
    .handler(async ({ data }): Promise<SendResult> => {
        if (!allow(getRequestIP({ xForwardedFor: true }) ?? 'unknown')) return { status: 'unavailable' };
        // … validace a odeslání e-mailu
    });
  • Statické HTML, cache a komprese řešíme přes Nitro routeRules: písma a assety s dlouhou cache, HTML s revalidací, předkomprimované JS a CSS.

A výsledek? Lighthouse dává bhpslabs.com 100 / 100 / 100 / 100 ve všech čtyřech kategoriích (Performance, Accessibility, Best Practices, SEO) a v nové kategorii Agentic Browsing 3 / 3, která měří, jak dobře se na webu vyzná AI agent. To není zásluha jednoho triku. Je to součet věcí výše: prerender, SSR bez zbytečného JavaScriptu, metadata u každé route a server, do kterého si můžete přidat, co potřebujete. Start nám v ničem z toho nepřekážel.

udalist.app

Udalist sbírá fotky a videa z akcí (svatby, oslavy, firemní eventy) do jedné sdílené galerie. Hosté naskenují QR kód a nahrávají přímo z prohlížeče v telefonu, bez aplikace a bez účtu. Je to naše vlajková loď a je tu víc aplikace než webu, takže je na něm vidět i druhá strana Startu:

  • 33 souborů rout s layouty bez cesty: _public pro marketing, _guest pro hosty a _secure pro přihlášené. Každá skupina má svůj layout a svá pravidla, a adresa přitom zůstává čistá.
  • TanStack Query žije v kontextu routeru, takže ho má k dispozici každý loader i beforeLoad. Data tahá z backendu v Kotlinu a v aplikaci ho používá kolem 25 souborů.
  • TanStack Form obsluhuje devět formulářů, od kontaktu po nastavení zabezpečení akce.
  • Sedm jazyků přes Paraglide, Sentry přes jeho oficiální SDK pro TanStack Start.
  • A/B test úvodní stránky běží přes server funkci, která přečte cookie a nastaví hlavičky odpovědi.
  • Cache pravidla pro Nitro jsou typovaná proti seznamu rout, který vygeneruje router. Když route přejmenujete nebo smažete, konfigurace cache přestane procházet kompilací:
import type { FileRouteTypes } from '../src/routeTree.gen';

type AppFullPath = FileRouteTypes['fullPaths'];

const MARKETING_PATHS_WITH_LONG_CACHE = [
    '/',
    '/pricing',
    '/faq',
    '/blog/',
    // …
] as const satisfies readonly AppFullPath[];

Překlep v adrese tak není tichá chyba v produkci, kdy stránka najednou přijde bez cache a bez bezpečnostních hlaviček. Je to červená čára v editoru. Přesně tohle mám na TanStacku rád.

Oba projekty mají schválně stejný základ. Jsme čtyřčlenný tým a nechceme udržovat dvě různé sestavy. Co vyřešíme na jednom, přeneseme na druhý.

Ekosystém je ta největší výhoda

Start sám o sobě je skvělý, ale jeho skutečná síla je v tom, že není sám:

  • TanStack Query pro serverová data a cache, standard, který znáte,
  • TanStack Router s typovou bezpečností, jakou jinde nenajdete,
  • TanStack Form pro typované formuláře bez ceremonií,
  • TanStack Table a Virtual pro tabulky a dlouhé seznamy,
  • a další: Store, Pacer, DB, AI, Devtools, Markdown…

Všechny knihovny mají stejnou filozofii: headless, typově bezpečné, framework-agnostické (React, Solid, Vue a další) a navržené tak, aby spolu dobře fungovaly. Když se naučíte jednu, ostatní vám přijdou povědomé. A když se rozhodnete jednu z nich nepoužít, nic se nerozbije.

Za ekosystémem navíc stojí silní partneři: Netlify, Vercel, Cloudflare, Railway, Render, Lovable, Clerk, WorkOS, Sentry, Prisma a další. To nejsou jen loga na webu. Jsou to SDK, šablony a integrace, které můžete použít hned.

Co není dokonalé

Abych nepsal jen chvalozpěv: Nitro v3, na kterém Start v produkci běží, je stále v betě. Funguje nám bez problémů, ale je dobré to vědět. A některé pokročilé věci (třeba RSC) se pořád vyvíjejí, takže pokud na nich chcete stavět celou aplikaci, počítejte s tím.

Ani jedno pro nás nebyl důvod Start odložit.

Jak začít

Pokud jste čekali na verzi 1.0, teď je ta chvíle:

pnpm create @tanstack/start@latest

Pak doporučuju dokumentaci Startu, a pokud migrujete z Next.js, má TanStack i průvodce migrací. A jak radí sám Tanner: pusťte na to klidně AI agenta. S aktuálními skills z balíčků, TypeScriptem a testy to zvládne překvapivě daleko.

Závěr

TanStack Start 1.0 je pro mě potvrzení něčeho, co jsem věděl už dlouho. Framework nemusí diktovat, jak má vypadat celá aplikace. Může vám dát silné, typované a explicitní nástroje a nechat rozhodnutí na vás.

Na tomhle webu i na Udalistu to máme v produkci a všechno funguje, jak má. Kdo se mě zeptá, co dnes zvolit na frontend, dostane jasnou odpověď: TanStack Start. A k němu zbytek TanStacku.

Díky, Tannere, a díky celému týmu kolem TanStacku. A pokud řešíte, jestli a jak na Start přejít, ozvěte se nám. Rádi poradíme.