TanStack Start Quickstart
This quickstart sets up Ory Elements in a TanStack Start application with @ory/tanstack-start.
The code used in the following quickstart is available in the TanStack Start example GitHub repository
How it works
TanStack Start runs route loaders on the server for the first request and in the browser on client-side navigation. To always send
the browser's Ory cookies, the app fetches flows in server functions. @ory/tanstack-start provides the helpers that run inside
them.
During local development and on preview deployments, a request middleware serves Ory on the app's own origin, so Ory's cookies are first-party. The middleware isn't supported in production: through the middleware, Ory sees your app server as the client instead of your users' browsers. In production, use a custom domain on Ory Network, or serve Ory on your own domain with the Ory Enterprise License, on the same site as your app.
Prerequisites
-
Create a TanStack Start application by following the TanStack Start getting started guide. This quickstart assumes the default
src/layout with file-based routes insrc/routes. -
Install the
@ory/elements-reactand@ory/tanstack-startpackages.- NPM
- PNPM
- Yarn
- Bun
npm install @ory/elements-react @ory/tanstack-startpnpm add @ory/elements-react @ory/tanstack-startyarn add @ory/elements-react @ory/tanstack-startbun add @ory/elements-react @ory/tanstack-start
Set up Ory Elements
-
Set the URL of your Ory project in the
.envfile. The server readsORY_SDK_URLandORY_PROJECT_API_TOKEN; the browser never sees them.You can find your Ory Network project URL in the Get started section of the Ory Console.
ORY_PROJECT_API_TOKENis optional. The proxy needs it for OIDC and SAML redirects. For preview deployments, create a dedicated API key, set it only in the preview environment, and never give it aVITE_prefix. -
Add the configuration for Ory Elements. Create
src/ory.config.ts:src/ory.config.ts -
Define the server functions. Create
src/ory.functions.ts. Each flow function validates the route's search params and returns the flow, or redirects the browser to Ory when the flow must be created or restarted.oryBaseUrlFnreturns the URL where the browser reaches Ory, fromgetOryBaseUrl.src/ory.functions.tsDefine each server function in your app, assigned to a top-level variable as shown. TanStack Start's compiler finds server functions by that variable.
-
Register the request middleware. Create
src/start.ts. The CSRF middleware rejects cross-site calls to your server functions. Oncesrc/start.tsdefines astartInstance, TanStack Start no longer adds its default CSRF middleware, so keep it in the list. SettrustedOriginsto the origins your local development server and preview deployments serve.src/start.ts -
Load the base URL in the root route and add the Ory Elements styles. Update
src/routes/__root.tsx, and createsrc/use-ory-base-url.tsto read the base URL in the pages:- __root.tsx
- use-ory-base-url.ts
src/routes/__root.tsxsrc/use-ory-base-url.ts -
Create a route for each self-service flow in
src/routes:login.tsx,registration.tsx,recovery.tsx,verification.tsx, andsettings.tsx. Each route passes its search params to the server function withloaderDeps, so the loader runs again when theflowparam changes. The flow carries the URL where the browser reaches Ory, so each page passes only the flow to the Ory Elements component. The settings page passes the base URL from the root route asbaseUrltoSessionProvider.- Login
- Registration
- Recovery
- Verification
- Settings
src/routes/login.tsxsrc/routes/registration.tsxsrc/routes/recovery.tsxsrc/routes/verification.tsxsrc/routes/settings.tsx -
Show the session and a logout link on the home page. Update
src/routes/index.tsx:src/routes/index.tsx -
Run the application on port 3000, the origin listed in
trustedOrigins:- NPM
- PNPM
- Yarn
- Bun
npm run devpnpm devyarn devbun devOpen
http://localhost:3000/registrationto create your first user. The other flows are at/login,/recovery,/verification, and/settings.
Preview deployments and production
Keep the middleware registered in every environment. On a preview deployment, it serves Ory on the preview's origin when that
origin is in trustedOrigins. Add a glob for your preview hosts that includes your team, for example
https://my-app-*-my-team.vercel.app.
An entry in trustedOrigins is an origin without a path, such as http://localhost:3000. To match several origins, use * in
the host as a glob. Each * matches one or more letters, digits, or hyphens and never a dot, so it stays inside one part of the
host name. A * can't make up the whole label right before a public suffix from the
Public Suffix List, such as vercel.app or com, so https://*.vercel.app is rejected. On a
hosting provider's domain, include your project and team in the glob, so it doesn't match other customers' deployments. The proxy
reports the app origin to Ory only for the origins in trustedOrigins. For any other origin, the app uses the Ory SDK URL and
logs a warning. Don't add your production origin. See
Trusted origins for more examples.
In production, Ory runs on a custom domain on the same site as your app, so the app uses ORY_SDK_URL whether the middleware is
registered or not.
The flow, session, and base URL functions mark their responses Cache-Control: private, no-store. On pages that are not 2xx, such
as a 404, they do so only when the middleware is registered. Don't let a shared cache, such as a CDN rule that caches every page,
store flow pages or server function responses.
The browser reaches Ory on the app's origin when the middleware handled the request, the origin is in trustedOrigins, and Ory is
on another site, and on ORY_SDK_URL otherwise.
Troubleshooting
When the browser would call Ory on another site, Ory's session cookies don't reach the app, and login or session checks fail.
@ory/tanstack-start then logs a warning once in the server log:
| Warning | Fix |
|---|---|
The Ory proxy handled a request for <origin>, which is not in trustedOrigins | In local development or a preview deployment, add the origin to trustedOrigins. In production, use a custom domain on the app's site. |
The app (<origin>) and Ory (<url>) are on different sites | The proxy didn't run for this request. Register oryProxyMiddleware in src/start.ts and call the helpers from server functions. |
The request's Host header is not a valid origin | Configure the reverse proxy in front of the app to forward the Host header the browser sent. |
Next steps
Customize the components, add your own styles, and integrate them into your application. See Theming to change the look and feel of the components.