diff --git a/docs/router/config.json b/docs/router/config.json
index 4758fb53fe6..5dfd26414ba 100644
--- a/docs/router/config.json
+++ b/docs/router/config.json
@@ -645,6 +645,10 @@
{
"label": "Framer Motion",
"to": "framework/solid/examples/with-framer-motion"
+ },
+ {
+ "label": "With tRPC",
+ "to": "framework/solid/examples/with-trpc"
}
]
}
diff --git a/examples/solid/with-trpc/.gitignore b/examples/solid/with-trpc/.gitignore
new file mode 100644
index 00000000000..ca63f498851
--- /dev/null
+++ b/examples/solid/with-trpc/.gitignore
@@ -0,0 +1,18 @@
+node_modules
+package-lock.json
+yarn.lock
+
+.DS_Store
+.cache
+.env
+.vercel
+.output
+/build/
+/api/
+/server/build
+/public/build# Sentry Config File
+.env.sentry-build-plugin
+/test-results/
+/playwright-report/
+/blob-report/
+/playwright/.cache/
diff --git a/examples/solid/with-trpc/.vscode/settings.json b/examples/solid/with-trpc/.vscode/settings.json
new file mode 100644
index 00000000000..00b5278e580
--- /dev/null
+++ b/examples/solid/with-trpc/.vscode/settings.json
@@ -0,0 +1,11 @@
+{
+ "files.watcherExclude": {
+ "**/routeTree.gen.ts": true
+ },
+ "search.exclude": {
+ "**/routeTree.gen.ts": true
+ },
+ "files.readonlyInclude": {
+ "**/routeTree.gen.ts": true
+ }
+}
diff --git a/examples/solid/with-trpc/README.md b/examples/solid/with-trpc/README.md
new file mode 100644
index 00000000000..115199d292c
--- /dev/null
+++ b/examples/solid/with-trpc/README.md
@@ -0,0 +1,6 @@
+# Example
+
+To run this example:
+
+- `npm install` or `yarn`
+- `npm start` or `yarn start`
diff --git a/examples/solid/with-trpc/index.html b/examples/solid/with-trpc/index.html
new file mode 100644
index 00000000000..ba530a2c7a9
--- /dev/null
+++ b/examples/solid/with-trpc/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ Vite App
+
+
+
+
+
+
diff --git a/examples/solid/with-trpc/package.json b/examples/solid/with-trpc/package.json
new file mode 100644
index 00000000000..bc00142dcba
--- /dev/null
+++ b/examples/solid/with-trpc/package.json
@@ -0,0 +1,32 @@
+{
+ "name": "tanstack-router-solid-example-with-trpc",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "dev": "pnpm tsx ./src/server/server.ts --watch",
+ "build": "pnpm run build:server && pnpm run build:client",
+ "build:client": "vite build && tsc --noEmit",
+ "build:server": "vite build --mode server",
+ "start": "NODE_ENV=production node dist/server/server.js"
+ },
+ "dependencies": {
+ "@tailwindcss/postcss": "^4.1.15",
+ "@tanstack/solid-router": "^1.135.2",
+ "@tanstack/solid-router-devtools": "^1.135.2",
+ "@tanstack/router-plugin": "^1.135.2",
+ "@trpc/client": "^11.4.3",
+ "@trpc/server": "^11.4.3",
+ "express": "^4.21.2",
+ "postcss": "^8.5.1",
+ "solid-js": "^1.9.10",
+ "redaxios": "^0.5.1",
+ "tailwindcss": "^4.1.15",
+ "zod": "^3.24.2"
+ },
+ "devDependencies": {
+ "@types/express": "^4.17.23",
+ "vite-plugin-solid": "^2.11.10",
+ "tsx": "^4.20.3",
+ "vite": "^7.1.7"
+ }
+}
diff --git a/examples/solid/with-trpc/postcss.config.mjs b/examples/solid/with-trpc/postcss.config.mjs
new file mode 100644
index 00000000000..a7f73a2d1d7
--- /dev/null
+++ b/examples/solid/with-trpc/postcss.config.mjs
@@ -0,0 +1,5 @@
+export default {
+ plugins: {
+ '@tailwindcss/postcss': {},
+ },
+}
diff --git a/examples/solid/with-trpc/src/main.tsx b/examples/solid/with-trpc/src/main.tsx
new file mode 100644
index 00000000000..d99d3054d70
--- /dev/null
+++ b/examples/solid/with-trpc/src/main.tsx
@@ -0,0 +1,37 @@
+import { render } from 'solid-js/web'
+import { RouterProvider, createRouter } from '@tanstack/solid-router'
+import { trpc } from './trpc'
+
+import { Spinner } from './routes/-components/spinner'
+import './styles.css'
+
+// Import the generated route tree
+import { routeTree } from './routeTree.gen'
+
+// Create a router instance
+const router = createRouter({
+ routeTree,
+ scrollRestoration: true,
+ defaultPreload: 'intent',
+ defaultPendingComponent: () => (
+
+
+
+ ),
+ context: {
+ trpc,
+ },
+})
+
+// Register the router instance for type safety
+declare module '@tanstack/solid-router' {
+ interface Register {
+ router: typeof router
+ }
+}
+
+const rootElement = document.getElementById('root')!
+
+if (!rootElement.innerHTML) {
+ render(() => , rootElement)
+}
diff --git a/examples/solid/with-trpc/src/routeTree.gen.ts b/examples/solid/with-trpc/src/routeTree.gen.ts
new file mode 100644
index 00000000000..fd935076940
--- /dev/null
+++ b/examples/solid/with-trpc/src/routeTree.gen.ts
@@ -0,0 +1,180 @@
+/* eslint-disable */
+
+// @ts-nocheck
+
+// noinspection JSUnusedGlobalSymbols
+
+// This file was automatically generated by TanStack Router.
+// You should NOT make any changes in this file as it will be overwritten.
+// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
+
+import { Route as rootRouteImport } from './routes/__root'
+import { Route as DashboardRouteImport } from './routes/dashboard'
+import { Route as IndexRouteImport } from './routes/index'
+import { Route as DashboardIndexRouteImport } from './routes/dashboard.index'
+import { Route as DashboardPostsRouteImport } from './routes/dashboard.posts'
+import { Route as DashboardPostsIndexRouteImport } from './routes/dashboard.posts.index'
+import { Route as DashboardPostsPostIdRouteImport } from './routes/dashboard.posts.$postId'
+
+const DashboardRoute = DashboardRouteImport.update({
+ id: '/dashboard',
+ path: '/dashboard',
+ getParentRoute: () => rootRouteImport,
+} as any)
+const IndexRoute = IndexRouteImport.update({
+ id: '/',
+ path: '/',
+ getParentRoute: () => rootRouteImport,
+} as any)
+const DashboardIndexRoute = DashboardIndexRouteImport.update({
+ id: '/',
+ path: '/',
+ getParentRoute: () => DashboardRoute,
+} as any)
+const DashboardPostsRoute = DashboardPostsRouteImport.update({
+ id: '/posts',
+ path: '/posts',
+ getParentRoute: () => DashboardRoute,
+} as any)
+const DashboardPostsIndexRoute = DashboardPostsIndexRouteImport.update({
+ id: '/',
+ path: '/',
+ getParentRoute: () => DashboardPostsRoute,
+} as any)
+const DashboardPostsPostIdRoute = DashboardPostsPostIdRouteImport.update({
+ id: '/$postId',
+ path: '/$postId',
+ getParentRoute: () => DashboardPostsRoute,
+} as any)
+
+export interface FileRoutesByFullPath {
+ '/': typeof IndexRoute
+ '/dashboard': typeof DashboardRouteWithChildren
+ '/dashboard/posts': typeof DashboardPostsRouteWithChildren
+ '/dashboard/': typeof DashboardIndexRoute
+ '/dashboard/posts/$postId': typeof DashboardPostsPostIdRoute
+ '/dashboard/posts/': typeof DashboardPostsIndexRoute
+}
+export interface FileRoutesByTo {
+ '/': typeof IndexRoute
+ '/dashboard': typeof DashboardIndexRoute
+ '/dashboard/posts/$postId': typeof DashboardPostsPostIdRoute
+ '/dashboard/posts': typeof DashboardPostsIndexRoute
+}
+export interface FileRoutesById {
+ __root__: typeof rootRouteImport
+ '/': typeof IndexRoute
+ '/dashboard': typeof DashboardRouteWithChildren
+ '/dashboard/posts': typeof DashboardPostsRouteWithChildren
+ '/dashboard/': typeof DashboardIndexRoute
+ '/dashboard/posts/$postId': typeof DashboardPostsPostIdRoute
+ '/dashboard/posts/': typeof DashboardPostsIndexRoute
+}
+export interface FileRouteTypes {
+ fileRoutesByFullPath: FileRoutesByFullPath
+ fullPaths:
+ | '/'
+ | '/dashboard'
+ | '/dashboard/posts'
+ | '/dashboard/'
+ | '/dashboard/posts/$postId'
+ | '/dashboard/posts/'
+ fileRoutesByTo: FileRoutesByTo
+ to: '/' | '/dashboard' | '/dashboard/posts/$postId' | '/dashboard/posts'
+ id:
+ | '__root__'
+ | '/'
+ | '/dashboard'
+ | '/dashboard/posts'
+ | '/dashboard/'
+ | '/dashboard/posts/$postId'
+ | '/dashboard/posts/'
+ fileRoutesById: FileRoutesById
+}
+export interface RootRouteChildren {
+ IndexRoute: typeof IndexRoute
+ DashboardRoute: typeof DashboardRouteWithChildren
+}
+
+declare module '@tanstack/solid-router' {
+ interface FileRoutesByPath {
+ '/dashboard': {
+ id: '/dashboard'
+ path: '/dashboard'
+ fullPath: '/dashboard'
+ preLoaderRoute: typeof DashboardRouteImport
+ parentRoute: typeof rootRouteImport
+ }
+ '/': {
+ id: '/'
+ path: '/'
+ fullPath: '/'
+ preLoaderRoute: typeof IndexRouteImport
+ parentRoute: typeof rootRouteImport
+ }
+ '/dashboard/': {
+ id: '/dashboard/'
+ path: '/'
+ fullPath: '/dashboard/'
+ preLoaderRoute: typeof DashboardIndexRouteImport
+ parentRoute: typeof DashboardRoute
+ }
+ '/dashboard/posts': {
+ id: '/dashboard/posts'
+ path: '/posts'
+ fullPath: '/dashboard/posts'
+ preLoaderRoute: typeof DashboardPostsRouteImport
+ parentRoute: typeof DashboardRoute
+ }
+ '/dashboard/posts/': {
+ id: '/dashboard/posts/'
+ path: '/'
+ fullPath: '/dashboard/posts/'
+ preLoaderRoute: typeof DashboardPostsIndexRouteImport
+ parentRoute: typeof DashboardPostsRoute
+ }
+ '/dashboard/posts/$postId': {
+ id: '/dashboard/posts/$postId'
+ path: '/$postId'
+ fullPath: '/dashboard/posts/$postId'
+ preLoaderRoute: typeof DashboardPostsPostIdRouteImport
+ parentRoute: typeof DashboardPostsRoute
+ }
+ }
+}
+
+interface DashboardPostsRouteChildren {
+ DashboardPostsPostIdRoute: typeof DashboardPostsPostIdRoute
+ DashboardPostsIndexRoute: typeof DashboardPostsIndexRoute
+}
+
+const DashboardPostsRouteChildren: DashboardPostsRouteChildren = {
+ DashboardPostsPostIdRoute: DashboardPostsPostIdRoute,
+ DashboardPostsIndexRoute: DashboardPostsIndexRoute,
+}
+
+const DashboardPostsRouteWithChildren = DashboardPostsRoute._addFileChildren(
+ DashboardPostsRouteChildren,
+)
+
+interface DashboardRouteChildren {
+ DashboardPostsRoute: typeof DashboardPostsRouteWithChildren
+ DashboardIndexRoute: typeof DashboardIndexRoute
+}
+
+const DashboardRouteChildren: DashboardRouteChildren = {
+ DashboardPostsRoute: DashboardPostsRouteWithChildren,
+ DashboardIndexRoute: DashboardIndexRoute,
+}
+
+const DashboardRouteWithChildren = DashboardRoute._addFileChildren(
+ DashboardRouteChildren,
+)
+
+const rootRouteChildren: RootRouteChildren = {
+ IndexRoute: IndexRoute,
+ DashboardRoute: DashboardRouteWithChildren,
+}
+export const routeTree = rootRouteImport
+ ._addFileChildren(rootRouteChildren)
+ ._addFileTypes()
diff --git a/examples/solid/with-trpc/src/routes/-components/spinner.tsx b/examples/solid/with-trpc/src/routes/-components/spinner.tsx
new file mode 100644
index 00000000000..e7bc03dbdbe
--- /dev/null
+++ b/examples/solid/with-trpc/src/routes/-components/spinner.tsx
@@ -0,0 +1,17 @@
+export function Spinner(props: { show?: boolean; wait?: `delay-${number}` }) {
+ return (
+
+ ⍥
+
+ )
+}
diff --git a/examples/solid/with-trpc/src/routes/__root.tsx b/examples/solid/with-trpc/src/routes/__root.tsx
new file mode 100644
index 00000000000..d6c8e7bb106
--- /dev/null
+++ b/examples/solid/with-trpc/src/routes/__root.tsx
@@ -0,0 +1,76 @@
+import {
+ Link,
+ Outlet,
+ createRootRouteWithContext,
+ useRouterState,
+} from '@tanstack/solid-router'
+import { TanStackRouterDevtools } from '@tanstack/solid-router-devtools'
+
+import { Spinner } from './-components/spinner'
+import type { trpc } from '../trpc'
+
+export interface RouterAppContext {
+ trpc: typeof trpc
+}
+
+export const Route = createRootRouteWithContext()({
+ component: RootComponent,
+})
+
+function RootComponent() {
+ const isFetching = useRouterState({ select: (s) => s.isLoading })
+
+ return (
+ <>
+
+
+
With tRPC
+ {/* Show a global spinner when the router is transitioning */}
+
+
+
+
+
+
+ {(
+ [
+ ['/', 'Home'],
+ ['/dashboard', 'Dashboard'],
+ ] as const
+ ).map(([to, label]) => {
+ return (
+
+
+ {label}
+
+
+ )
+ })}
+
+
+ {/* Render our first route match */}
+
+
+
+
+
+ >
+ )
+}
diff --git a/examples/solid/with-trpc/src/routes/dashboard.index.tsx b/examples/solid/with-trpc/src/routes/dashboard.index.tsx
new file mode 100644
index 00000000000..8c2aa43e7d2
--- /dev/null
+++ b/examples/solid/with-trpc/src/routes/dashboard.index.tsx
@@ -0,0 +1,19 @@
+import { createFileRoute } from '@tanstack/solid-router'
+
+export const Route = createFileRoute('/dashboard/')({
+ loader: ({ context: { trpc } }) => trpc.posts.query(),
+ component: DashboardIndexComponent,
+})
+
+function DashboardIndexComponent() {
+ const posts = Route.useLoaderData()
+
+ return (
+
+
+ Welcome to the dashboard! You have{' '}
+ {posts().length} total posts .
+
+
+ )
+}
diff --git a/examples/solid/with-trpc/src/routes/dashboard.posts.$postId.tsx b/examples/solid/with-trpc/src/routes/dashboard.posts.$postId.tsx
new file mode 100644
index 00000000000..cc967b0b76a
--- /dev/null
+++ b/examples/solid/with-trpc/src/routes/dashboard.posts.$postId.tsx
@@ -0,0 +1,90 @@
+import * as Solid from 'solid-js'
+import { Link, createFileRoute } from '@tanstack/solid-router'
+import { z } from 'zod'
+
+export const Route = createFileRoute('/dashboard/posts/$postId')({
+ validateSearch: z.object({
+ showNotes: z.boolean().optional(),
+ notes: z.string().optional(),
+ }),
+ loader: async ({
+ context: { trpc },
+ params: { postId },
+ }): Promise<{ id: string; title: string } | undefined> =>
+ trpc.post.query(postId),
+ component: DashboardPostsPostIdComponent,
+})
+
+function DashboardPostsPostIdComponent() {
+ const post = Route.useLoaderData()
+ const search = Route.useSearch()
+ const navigate = Route.useNavigate()
+
+ const [notes, setNotes] = Solid.createSignal(search().notes ?? ``)
+
+ Solid.createEffect(
+ Solid.on(notes, () => {
+ navigate({
+ search: (old) => ({ ...old, notes: notes() ? notes() : undefined }),
+ replace: true,
+ params: true,
+ })
+ }),
+ )
+
+ if (!post()) {
+ return Post not found
+ }
+
+ return (
+
+
+
+
({
+ ...old,
+ showNotes: old.showNotes ? undefined : true,
+ })}
+ params={true}
+ class="text-blue-700"
+ >
+ {search().showNotes ? 'Close Notes' : 'Show Notes'}{' '}
+
+ {search().showNotes ? (
+ <>
+
+ >
+ ) : null}
+
+
+ )
+}
diff --git a/examples/solid/with-trpc/src/routes/dashboard.posts.index.tsx b/examples/solid/with-trpc/src/routes/dashboard.posts.index.tsx
new file mode 100644
index 00000000000..5841e1fefdd
--- /dev/null
+++ b/examples/solid/with-trpc/src/routes/dashboard.posts.index.tsx
@@ -0,0 +1,9 @@
+import { createFileRoute } from '@tanstack/solid-router'
+
+export const Route = createFileRoute('/dashboard/posts/')({
+ component: DashboardPostsIndexComponent,
+})
+
+function DashboardPostsIndexComponent() {
+ return Select a post to view.
+}
diff --git a/examples/solid/with-trpc/src/routes/dashboard.posts.tsx b/examples/solid/with-trpc/src/routes/dashboard.posts.tsx
new file mode 100644
index 00000000000..3ca324afc11
--- /dev/null
+++ b/examples/solid/with-trpc/src/routes/dashboard.posts.tsx
@@ -0,0 +1,58 @@
+import * as Solid from 'solid-js'
+import {
+ Link,
+ MatchRoute,
+ Outlet,
+ createFileRoute,
+} from '@tanstack/solid-router'
+
+import { Spinner } from './-components/spinner'
+
+export const Route = createFileRoute('/dashboard/posts')({
+ loader: ({ context: { trpc } }) => trpc.posts.query(),
+ component: DashboardPostsComponent,
+})
+
+function DashboardPostsComponent() {
+ const posts = Route.useLoaderData()
+
+ return (
+
+
+
+ {(post) => {
+ return (
+
+
+
+ #{post.id} - {post.title.slice(0, 10)}{' '}
+
+ {(match) => }
+
+
+
+
+ )
+ }}
+
+
+
+
+
+
+ )
+}
diff --git a/examples/solid/with-trpc/src/routes/dashboard.tsx b/examples/solid/with-trpc/src/routes/dashboard.tsx
new file mode 100644
index 00000000000..e48e33e8979
--- /dev/null
+++ b/examples/solid/with-trpc/src/routes/dashboard.tsx
@@ -0,0 +1,46 @@
+import { Link, Outlet, createFileRoute } from '@tanstack/solid-router'
+
+export const Route = createFileRoute('/dashboard')({
+ component: DashboardComponent,
+})
+
+function DashboardComponent() {
+ return (
+ <>
+
+
Dashboard
+
+ 1 New Invoice
+
+
+
+ {(
+ [
+ ['.', 'Summary'],
+ ['/dashboard/posts', 'Posts'],
+ ] as const
+ ).map(([to, label]) => {
+ return (
+
+ {label}
+
+ )
+ })}
+
+
+
+ >
+ )
+}
diff --git a/examples/solid/with-trpc/src/routes/index.tsx b/examples/solid/with-trpc/src/routes/index.tsx
new file mode 100644
index 00000000000..61c9a650229
--- /dev/null
+++ b/examples/solid/with-trpc/src/routes/index.tsx
@@ -0,0 +1,36 @@
+import { Link, createFileRoute } from '@tanstack/solid-router'
+
+export const Route = createFileRoute('/')({
+ component: IndexComponent,
+})
+
+function IndexComponent() {
+ return (
+
+
Welcome Home!
+
+
+ 1 New Invoice
+
+
+
+ As you navigate around take note of the UX. It should feel
+ suspense-like, where routes are only rendered once all of their data and
+ elements are ready.
+
+ To exaggerate async effects, play with the artificial request delay
+ slider in the bottom-left corner.
+
+ The last 2 sliders determine if link-hover preloading is enabled (and
+ how long those preloads stick around) and also whether to cache rendered
+ route data (and for how long). Both of these default to 0 (or off).
+
+
+ )
+}
diff --git a/examples/solid/with-trpc/src/server/server.ts b/examples/solid/with-trpc/src/server/server.ts
new file mode 100644
index 00000000000..b2b3fd24855
--- /dev/null
+++ b/examples/solid/with-trpc/src/server/server.ts
@@ -0,0 +1,85 @@
+import path from 'node:path'
+import url from 'node:url'
+import * as fs from 'node:fs'
+import express from 'express'
+import { trpcMiddleWare } from './trpc'
+
+const PORT =
+ typeof process.env.PORT !== 'undefined'
+ ? parseInt(process.env.PORT, 10)
+ : 3000
+const HMR_PORT =
+ typeof process.env.HMR_PORT !== 'undefined'
+ ? parseInt(process.env.HMR_PORT, 10)
+ : 3001
+
+const isTest = process.env.NODE_ENV === 'test' || !!process.env.VITE_TEST_BUILD
+
+const __filename = url.fileURLToPath(import.meta.url)
+const __dirname = path.dirname(__filename)
+
+export const createServer = async (
+ root = process.cwd(),
+ isProd = process.env.NODE_ENV === 'production',
+) => {
+ const app = express()
+
+ app.use('/trpc', trpcMiddleWare as any)
+
+ if (!isProd) {
+ const vite = await import('vite')
+ const viteServer = await vite.createServer({
+ root,
+ logLevel: isTest ? 'error' : 'info',
+ server: {
+ middlewareMode: true,
+ watch: {
+ // During tests we edit the files too fast and sometimes chokidar
+ // misses change events, so enforce polling for consistency
+ usePolling: true,
+ interval: 100,
+ },
+ hmr: {
+ port: HMR_PORT,
+ },
+ },
+ appType: 'custom',
+ })
+
+ // Use vite's connect instance as middleware
+ app.use(viteServer.middlewares)
+
+ // Handle any requests that don't match an API route by serving the React app's index.html
+ app.get('*', async (req, res, next) => {
+ try {
+ let html = fs.readFileSync(path.resolve(root, 'index.html'), 'utf-8')
+
+ // Transform HTML using Vite plugins.
+ html = await viteServer.transformIndexHtml(req.url, html)
+
+ res.send(html)
+ } catch (e) {
+ return next(e)
+ }
+ })
+
+ return { app }
+ } else {
+ app.use(express.static(path.resolve(__dirname, '../client')))
+
+ // Handle any requests that don't match an API route by serving the React app's index.html
+ app.get('*', (req, res) => {
+ res.sendFile(path.resolve(__dirname, '../client', 'index.html'))
+ })
+ }
+
+ return { app }
+}
+
+if (!isTest) {
+ createServer().then(({ app }) =>
+ app.listen(PORT, () => {
+ console.info(`Server available at: http://localhost:${PORT}`)
+ }),
+ )
+}
diff --git a/examples/solid/with-trpc/src/server/trpc.ts b/examples/solid/with-trpc/src/server/trpc.ts
new file mode 100644
index 00000000000..f80de1199d1
--- /dev/null
+++ b/examples/solid/with-trpc/src/server/trpc.ts
@@ -0,0 +1,41 @@
+import { initTRPC } from '@trpc/server'
+import { createExpressMiddleware } from '@trpc/server/adapters/express'
+import type { CreateExpressContextOptions } from '@trpc/server/adapters/express'
+
+const createTRPContext = ({ req, res }: CreateExpressContextOptions) => ({})
+
+type TRPCContext = Awaited>
+
+const t = initTRPC.context().create()
+
+const POSTS = [
+ { id: '1', title: 'First post' },
+ { id: '2', title: 'Second post' },
+ { id: '3', title: 'Third post' },
+ { id: '4', title: 'Fourth post' },
+ { id: '5', title: 'Fifth post' },
+ { id: '6', title: 'Sixth post' },
+ { id: '7', title: 'Seventh post' },
+ { id: '8', title: 'Eighth post' },
+ { id: '9', title: 'Ninth post' },
+ { id: '10', title: 'Tenth post' },
+]
+
+export const appRouter = t.router({
+ hello: t.procedure.query(() => 'Hello world!'),
+ posts: t.procedure.query(async (_) => {
+ await new Promise((resolve) => setTimeout(resolve, 1000))
+ return POSTS
+ }),
+ post: t.procedure.input(String).query(async (req) => {
+ await new Promise((resolve) => setTimeout(resolve, 500))
+ return POSTS.find((p) => p.id === req.input)
+ }),
+})
+
+export const trpcMiddleWare = createExpressMiddleware({
+ router: appRouter,
+ createContext: createTRPContext,
+})
+
+export type AppRouter = typeof appRouter
diff --git a/examples/solid/with-trpc/src/styles.css b/examples/solid/with-trpc/src/styles.css
new file mode 100644
index 00000000000..37a1064738a
--- /dev/null
+++ b/examples/solid/with-trpc/src/styles.css
@@ -0,0 +1,21 @@
+@import 'tailwindcss';
+
+@layer base {
+ *,
+ ::after,
+ ::before,
+ ::backdrop,
+ ::file-selector-button {
+ border-color: var(--color-gray-200, currentcolor);
+ }
+}
+
+html {
+ color-scheme: light dark;
+}
+* {
+ @apply border-gray-200 dark:border-gray-800;
+}
+body {
+ @apply bg-gray-50 text-gray-950 dark:bg-gray-900 dark:text-gray-200;
+}
diff --git a/examples/solid/with-trpc/src/trpc.ts b/examples/solid/with-trpc/src/trpc.ts
new file mode 100644
index 00000000000..492361b3b9a
--- /dev/null
+++ b/examples/solid/with-trpc/src/trpc.ts
@@ -0,0 +1,13 @@
+import { createTRPCClient, httpBatchLink } from '@trpc/client'
+import type { AppRouter } from './server/trpc'
+
+export const trpc = createTRPCClient({
+ links: [
+ httpBatchLink({
+ // since we are using Vite, the server is running on the same port,
+ // this means in dev the url is `http://localhost:3000/trpc`
+ // and since its from the same origin, we don't need to explicitly set the full URL
+ url: '/trpc',
+ }),
+ ],
+})
diff --git a/examples/solid/with-trpc/tsconfig.json b/examples/solid/with-trpc/tsconfig.json
new file mode 100644
index 00000000000..84552169922
--- /dev/null
+++ b/examples/solid/with-trpc/tsconfig.json
@@ -0,0 +1,15 @@
+{
+ "compilerOptions": {
+ "strict": true,
+ "esModuleInterop": true,
+ "jsx": "preserve",
+ "jsxImportSource": "solid-js",
+ "target": "ES2022",
+ "module": "ES2022",
+ "moduleResolution": "bundler",
+ "skipLibCheck": true,
+ "lib": ["DOM", "DOM.Iterable", "ES2022"],
+ "types": ["node", "vite/client"]
+ },
+ "include": ["src", "vite.config.ts", "tsup.config.ts"]
+}
diff --git a/examples/solid/with-trpc/vite.config.ts b/examples/solid/with-trpc/vite.config.ts
new file mode 100644
index 00000000000..38953f0a2c3
--- /dev/null
+++ b/examples/solid/with-trpc/vite.config.ts
@@ -0,0 +1,47 @@
+import url from 'node:url'
+import path from 'node:path'
+import { defineConfig } from 'vite'
+import solid from 'vite-plugin-solid'
+import { tanstackRouter } from '@tanstack/router-plugin/vite'
+import type { BuildEnvironmentOptions } from 'vite'
+
+const __filename = url.fileURLToPath(import.meta.url)
+const __dirname = path.dirname(__filename)
+
+// Client Build Configuration
+const clientBuildConfig: BuildEnvironmentOptions = {
+ outDir: 'dist/client',
+ emitAssets: true,
+ copyPublicDir: true,
+ emptyOutDir: true,
+}
+
+// Server Build Configuration
+const serverBuildConfig: BuildEnvironmentOptions = {
+ ssr: true,
+ outDir: 'dist/server',
+ copyPublicDir: false,
+ emptyOutDir: true,
+ rollupOptions: {
+ input: path.resolve(__dirname, 'src/server/server.ts'),
+ output: {
+ entryFileNames: '[name].js',
+ chunkFileNames: 'assets/[name]-[hash].js',
+ assetFileNames: 'assets/[name]-[hash][extname]',
+ },
+ },
+}
+
+// https://vitejs.dev/config/
+export default defineConfig((configEnv) => {
+ return {
+ plugins: [
+ tanstackRouter({
+ target: 'solid',
+ autoCodeSplitting: true,
+ }),
+ solid(),
+ ],
+ build: configEnv.mode === 'server' ? serverBuildConfig : clientBuildConfig,
+ }
+})
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index df9b8f06807..2e4fd518d17 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -7927,6 +7927,128 @@ importers:
specifier: ^2.11.10
version: 2.11.10(@testing-library/jest-dom@6.6.3)(solid-js@1.9.10)(vite@7.1.7(@types/node@22.10.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1))
+ examples/solid/with-trpc:
+ dependencies:
+ '@tailwindcss/postcss':
+ specifier: ^4.1.15
+ version: 4.1.15
+ '@tanstack/router-plugin':
+ specifier: workspace:*
+ version: link:../../../packages/router-plugin
+ '@tanstack/solid-router':
+ specifier: ^1.135.2
+ version: link:../../../packages/solid-router
+ '@tanstack/solid-router-devtools':
+ specifier: workspace:^
+ version: link:../../../packages/solid-router-devtools
+ '@trpc/client':
+ specifier: ^11.4.3
+ version: 11.4.3(@trpc/server@11.4.3(typescript@5.9.2))(typescript@5.9.2)
+ '@trpc/server':
+ specifier: ^11.4.3
+ version: 11.4.3(typescript@5.9.2)
+ express:
+ specifier: ^4.21.2
+ version: 4.21.2
+ postcss:
+ specifier: ^8.5.1
+ version: 8.5.6
+ redaxios:
+ specifier: ^0.5.1
+ version: 0.5.1
+ solid-js:
+ specifier: 1.9.10
+ version: 1.9.10
+ tailwindcss:
+ specifier: ^4.1.15
+ version: 4.1.17
+ zod:
+ specifier: ^3.24.2
+ version: 3.25.57
+ devDependencies:
+ '@types/express':
+ specifier: ^4.17.23
+ version: 4.17.23
+ tsx:
+ specifier: ^4.20.3
+ version: 4.20.3
+ vite:
+ specifier: ^7.1.7
+ version: 7.1.7(@types/node@22.10.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1)
+ vite-plugin-solid:
+ specifier: ^2.11.10
+ version: 2.11.10(@testing-library/jest-dom@6.6.3)(solid-js@1.9.10)(vite@7.1.7(@types/node@22.10.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1))
+
+ examples/solid/with-trpc-react-query:
+ dependencies:
+ '@tailwindcss/postcss':
+ specifier: ^4.1.15
+ version: 4.1.15
+ '@tanstack/react-query':
+ specifier: ^5.90.7
+ version: 5.90.7(react@19.2.0)
+ '@tanstack/react-query-devtools':
+ specifier: ^5.90.0
+ version: 5.90.2(@tanstack/react-query@5.90.7(react@19.2.0))(react@19.2.0)
+ '@tanstack/react-router':
+ specifier: workspace:*
+ version: link:../../../packages/react-router
+ '@tanstack/react-router-devtools':
+ specifier: workspace:^
+ version: link:../../../packages/react-router-devtools
+ '@tanstack/router-plugin':
+ specifier: workspace:*
+ version: link:../../../packages/router-plugin
+ '@trpc/client':
+ specifier: ^11.4.3
+ version: 11.4.3(@trpc/server@11.4.3(typescript@5.9.2))(typescript@5.9.2)
+ '@trpc/server':
+ specifier: ^11.4.3
+ version: 11.4.3(typescript@5.9.2)
+ '@trpc/tanstack-react-query':
+ specifier: ^11.4.3
+ version: 11.4.3(@tanstack/react-query@5.90.7(react@19.2.0))(@trpc/client@11.4.3(@trpc/server@11.4.3(typescript@5.9.2))(typescript@5.9.2))(@trpc/server@11.4.3(typescript@5.9.2))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.9.2)
+ express:
+ specifier: ^4.21.2
+ version: 4.21.2
+ postcss:
+ specifier: ^8.5.1
+ version: 8.5.6
+ react:
+ specifier: ^19.2.0
+ version: 19.2.0
+ react-dom:
+ specifier: ^19.2.0
+ version: 19.2.0(react@19.2.0)
+ redaxios:
+ specifier: ^0.5.1
+ version: 0.5.1
+ tailwindcss:
+ specifier: ^4.1.15
+ version: 4.1.17
+ zod:
+ specifier: ^3.24.2
+ version: 3.25.57
+ devDependencies:
+ '@types/express':
+ specifier: ^4.17.23
+ version: 4.17.23
+ '@types/react':
+ specifier: ^19.2.2
+ version: 19.2.2
+ '@types/react-dom':
+ specifier: ^19.2.2
+ version: 19.2.2(@types/react@19.2.2)
+ '@vitejs/plugin-react':
+ specifier: ^4.3.4
+ version: 4.7.0(vite@7.1.7(@types/node@22.10.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1))
+ tsx:
+ specifier: ^4.20.3
+ version: 4.20.3
+ vite:
+ specifier: ^7.1.7
+ version: 7.1.7(@types/node@22.10.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1)
+
packages/arktype-adapter:
devDependencies:
'@tanstack/react-router':