Skip to content

Commit fbbd60c

Browse files
Audit and harden partner experience (#1063)
* Audit TanStack partner experience * Harden partner integrations and directory
1 parent 5a37c4f commit fbbd60c

36 files changed

Lines changed: 2452 additions & 1044 deletions

.agents/analytics.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,9 @@ User changed the filter state on the partners directory.
101101

102102
User clicked a "get in touch", "let's chat", or "become a partner" CTA.
103103

104-
| Prop | Type | Notes |
105-
| ----------- | ---- | ---------------------------------------------------------- |
106-
| `placement` | enum | `partners_index_cta`, `library_callout`, `docs_right_rail` |
104+
| Prop | Type | Notes |
105+
| ----------- | ---- | ---------------------------- |
106+
| `placement` | enum | See `PartnerPlacement` below |
107107

108108
---
109109

@@ -191,6 +191,7 @@ User took an action on the generated result. Single event with `action` prop cov
191191
| `ecosystem_game` | 3D ecosystem game islands |
192192
| `partners_index_cta` | "Get in touch" mailto on `/partners` |
193193
| `library_callout` | "Let's chat" callout per library |
194+
| `navbar` | "Partnership Inquiry" mailto in the Support menu |
194195

195196
### `BuilderAction`
196197

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
"@tanstack/ai-anthropic": "^0.10.1",
6262
"@tanstack/ai-client": "^0.11.3",
6363
"@tanstack/ai-openai": "^0.9.5",
64-
"@tanstack/create": "^0.68.4",
64+
"@tanstack/create": "^0.69.0",
6565
"@tanstack/highlight": "^0.0.3",
6666
"@tanstack/markdown": "^0.0.11",
6767
"@tanstack/pacer": "^0.21.1",

pnpm-lock.yaml

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/blog/netlify-partnership.md

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,32 @@
11
---
22
title: TanStack + Netlify Partnership
33
published: 2025-03-18
4-
excerpt: Netlify is now the official deployment partner for TanStack Start. Their focus on speed, simplicity, and flexibility aligns perfectly with our vision for full-stack development.
4+
excerpt: Netlify is an official hosting partner for TanStack Start, with a Vite integration for deploying full-stack apps and an official starter template.
55
authors:
66
- Tanner Linsley
77
---
88

99
![Netlify Header](/blog-assets/netlify-partnership/header.jpg)
1010

11-
We’re excited to announce that **Netlify** is now the **Official Deployment Partner** for **TanStack Start**! Together, we’re making it easier than ever for developers to build and deploy modern, type-safe, and user-focused web applications.
11+
**Netlify is an official hosting partner for TanStack Start.** The practical result is a supported deployment path through [`@netlify/vite-plugin-tanstack-start`](https://www.npmjs.com/package/@netlify/vite-plugin-tanstack-start), including SSR, Server Routes, Server Functions, middleware, and local Netlify platform emulation.
1212

13-
Netlify has earned its reputation as the ultimate deployment platform for modern web developers. Its focus on speed, simplicity, modularity, and flexibility aligns perfectly with TanStack Start’s vision for full-stack development. Here’s why Netlify stands out:
13+
## TanStack Start on Netlify
1414

15-
- **No-config simplicity** – Deploy your TanStack Start apps in seconds, with zero setup hassle.
16-
- **Serverless power** – Netlify Functions enable dynamic, real-time features effortlessly.
17-
- **Global performance** – Fast, reliable apps served from Netlify’s global edge network.
18-
- **Developer-first tools** – Instant previews, automated workflows, and seamless integrations make building a joy.
15+
Netlify’s Vite integration configures TanStack Start for its full-stack runtime while keeping the usual Vite development loop. Git-based continuous deployment creates Deploy Previews for pull and merge requests. Teams can also enable branch deploys for selected or all non-production branches.
1916

20-
## Why Netlify?
17+
Netlify also maintains a [full-stack TanStack Start chat template](https://github.com/netlify-templates/tanstack-template) built with TanStack Router, TanStack Store, Claude, and optional Sentry and Convex integrations. You can deploy that template directly, or create a new Netlify-ready project with the TanStack CLI:
2118

22-
Netlify is more than just a deployment provider. They’ve worked closely with us to ensure that deploying TanStack Start applications is not just fast, but optimized for the best possible developer experience. Whether you’re building interactive UIs, data-heavy dashboards, real-time tools, or AI-powered applications, Netlify’s platform makes the process seamless.
23-
24-
As part of this partnership, Netlify has also launched a **full-stack AI chatbot starter template** that showcases TanStack Start’s powerful data management capabilities alongside Netlify Functions. This template provides:
25-
26-
- **Real-time data handling** with TanStack Query
27-
- **Efficient routing** with TanStack Router
28-
- **Seamless server function integration** with Netlify
29-
- **A production-ready deployment configuration**
30-
31-
To get started with the template, simply run:
32-
33-
```
34-
npx create-tsrouter-app@latest <name> --template file-router --add-ons tanchat
19+
```bash
20+
npx @tanstack/cli create my-app --deployment netlify
3521
```
3622

37-
This template is a great way to explore how TanStack Start and Netlify work together to simplify modern web development.
38-
39-
## What’s Next?
23+
The CLI installs and configures the Netlify deployment target, so the generated project is ready for the Netlify CLI or a Git-connected deployment.
4024

41-
We’re just getting started. Expect more updates, new features, and deeper collaboration between TanStack Start and Netlify. Stay tuned for success stories, guides, and real-world examples showcasing what’s possible with this powerful combination.
25+
## Deploy a TanStack Start app
4226

43-
Additionally, join us March 31 for a **special TanStack Start episode on [Netlify’s Remote Desk series](https://www.netlify.com/webinars/netlify-remote-desk/)**. We’ll dive into live demos, developer tips, and an exclusive Q&A to show how to unlock the full potential of TanStack Start on Netlify.
27+
For a new project, use the command above and follow the generated setup. For an existing app, add the Netlify Vite plugin and deploy with `npx netlify deploy`.
4428

45-
**Ready to dive in?** Check out the [TanStack Start docs](/start/latest/docs/framework/react/overview), explore the deployment guides, and start building with Netlify today.
29+
- [TanStack Start hosting guide](https://tanstack.com/start/latest/docs/framework/react/guide/hosting#netlify--official-partner)
30+
- [Netlify’s TanStack Start template](https://github.com/netlify-templates/tanstack-template)
4631

47-
A huge thank you to Netlify for supporting and empowering developers. Let’s build something incredible together! 🚀
32+
Netlify’s support helps fund TanStack’s open-source work while giving Start users a deployment path maintained by both teams.

src/blog/openrouter-partnership.md

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
---
22
title: TanStack + OpenRouter Partnership
33
published: 2026-03-09
4-
excerpt: OpenRouter is now an official TanStack sponsor. The most concrete result is already shipped — a first-class TanStack AI adapter giving you access to 300+ models from 60+ providers through a single API.
4+
excerpt: OpenRouter is an official TanStack sponsor, with a first-class TanStack AI adapter for accessing hundreds of models through one API.
55
authors:
66
- Tanner Linsley
77
---
88

99
![TanStack + OpenRouter](/blog-assets/openrouter-partnership/header.png)
1010

11-
**OpenRouter is now an official TanStack sponsor.** And the most concrete expression of that is already shipped: [`@tanstack/ai-openrouter`](https://tanstack.com/ai/latest/docs/adapters/openrouter)a first-class TanStack AI adapter that gives you access to 300+ models from 60+ providers through a single, unified API.
11+
**OpenRouter is now an official TanStack sponsor.** The most concrete expression of that is already shipped: [`@tanstack/ai-openrouter`](https://tanstack.com/ai/latest/docs/adapters/openrouter), a first-class TanStack AI adapter that gives you access to hundreds of models through one API.
1212

1313
## Why OpenRouter
1414

1515
When we started building TanStack AI, one of our core beliefs was that you shouldn't have to bet your integration on a single provider. The AI model landscape is moving faster than anyone can predict. The model that wins this quarter might not be the one you want next quarter, and rewriting your AI layer every time a new frontier model drops is exactly the kind of undifferentiated toil we want to help you avoid.
1616

17-
OpenRouter solves this cleanly. One API key. One integration. GPT-5, Claude, Gemini, Llama, Mistral, DeepSeekand whatever ships next month. When you want to try a different model, you change a string. When a provider goes down, OpenRouter routes around it automatically. That's the kind of leverage I want TanStack developers to have.
17+
OpenRouter solves this cleanly. One API key and one integration for GPT, Claude, Gemini, Llama, Mistral, DeepSeek, and whatever ships next. When you want to try a different model, you change a string. When a provider goes down, OpenRouter can route around it. That's the kind of leverage I want TanStack developers to have.
1818

1919
## The Adapter
2020

@@ -32,26 +32,25 @@ const stream = chat({
3232
})
3333
```
3434

35-
Swap the model string for any of the [300+ models on OpenRouter](https://openrouter.ai/models?utm_source=tanstack). Everything else stays the same.
35+
Swap the model string for any model in the [OpenRouter catalog](https://openrouter.ai/models?utm_source=tanstack). Everything else stays the same.
3636

3737
One feature I particularly love is the auto-router with fallbacks. It's dead simple to set up and gives your app real production resilience without any retry logic of your own:
3838

3939
```typescript
4040
const stream = chat({
4141
adapter: openRouterText('openrouter/auto'),
4242
messages,
43-
providerOptions: {
43+
modelOptions: {
4444
models: [
45-
'openai/gpt-5',
45+
'openai/gpt-5.5',
4646
'anthropic/claude-sonnet-4.5',
47-
'google/gemini-3-pro-preview',
47+
'google/gemini-3.1-pro-preview',
4848
],
49-
route: 'fallback',
5049
},
5150
})
5251
```
5352

54-
If the primary model fails or gets rate-limited, OpenRouter falls through to the next one. No outage pages, no extra infrastructure.
53+
If the primary model is unavailable, OpenRouter falls through the configured list. The fallback order stays in the request instead of becoming hand-written retry logic.
5554

5655
## Jack's Image Generation Demo
5756

@@ -69,7 +68,7 @@ Our own Jack Herrington put together a demo showing off TanStack AI with the Ope
6968
7069
## What This Means Going Forward
7170

72-
OpenRouter's sponsorship of TanStack means the adapter is actively maintained, tested, and will stay in sync with both libraries as they evolve. More importantly, both teams are genuinely aligned on the same goal: give developers the most flexible AI integration possible without locking them into anything.
71+
The sponsorship supports ongoing maintenance and testing as TanStack AI and OpenRouter evolve. More importantly, both teams are aligned on the same goal: give developers a flexible AI integration without locking them into a single model provider.
7372

7473
If you're building AI features with TanStack, the OpenRouter adapter is the one I'd reach for first.
7574

src/builder/api/create-worker.ts

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ type GeneratedTemplateContext = WorkerTemplateContext & {
2121
projectName: unknown
2222
typescript: unknown
2323
tailwind: unknown
24+
blank: unknown
2425
js: unknown
2526
jsx: unknown
2627
fileRouter: unknown
@@ -62,6 +63,7 @@ type WorkerAddOnPhase = WorkerAddOnManifest['phase']
6263
type WorkerAddOnCategory = NonNullable<WorkerAddOnManifest['category']>
6364
type WorkerAddOnExclusive = NonNullable<WorkerAddOnManifest['exclusive']>[number]
6465
type WorkerAddOnEnvVar = NonNullable<WorkerAddOnManifest['envVars']>[number]
66+
type WorkerAddOnPartner = NonNullable<WorkerAddOnManifest['partner']>
6567
type WorkerAddOnOptions = NonNullable<WorkerAddOnManifest['options']>
6668
type WorkerAddOnOption = WorkerAddOnOptions[string]
6769
type WorkerAddOnPackageAdditions = NonNullable<
@@ -71,6 +73,10 @@ type GeneratedStringRecord = Record<string, string | undefined>
7173
type GeneratedAddOnPackageAdditions = {
7274
dependencies?: GeneratedStringRecord
7375
devDependencies?: GeneratedStringRecord
76+
engines?: GeneratedStringRecord
77+
pnpm?: {
78+
onlyBuiltDependencies?: Array<string>
79+
}
7480
scripts?: GeneratedStringRecord
7581
}
7682
type GeneratedAddOnEnvVar = Omit<WorkerAddOnEnvVar, 'file'> & {
@@ -79,6 +85,9 @@ type GeneratedAddOnEnvVar = Omit<WorkerAddOnEnvVar, 'file'> & {
7985
type GeneratedAddOnOption = Omit<WorkerAddOnOption, 'type'> & {
8086
type: string
8187
}
88+
type GeneratedAddOnPartner = Omit<WorkerAddOnPartner, 'tier'> & {
89+
tier: string
90+
}
8291
type GeneratedAddOnOptions = Record<string, GeneratedAddOnOption | undefined>
8392
type GeneratedAddOnFields = {
8493
type: string
@@ -87,6 +96,7 @@ type GeneratedAddOnFields = {
8796
exclusive?: Array<string>
8897
envVars?: Array<GeneratedAddOnEnvVar>
8998
options?: GeneratedAddOnOptions
99+
partner?: GeneratedAddOnPartner
90100
}
91101
type GeneratedAddOnManifest = Omit<
92102
WorkerAddOnManifest,
@@ -96,6 +106,7 @@ type GeneratedAddOnManifest = Omit<
96106
| 'exclusive'
97107
| 'envVars'
98108
| 'options'
109+
| 'partner'
99110
| 'packageAdditions'
100111
> &
101112
GeneratedAddOnFields & {
@@ -109,6 +120,7 @@ type GeneratedAddOnMetadata = Omit<
109120
| 'exclusive'
110121
| 'envVars'
111122
| 'options'
123+
| 'partner'
112124
| 'packageAdditions'
113125
> &
114126
GeneratedAddOnFields & {
@@ -136,6 +148,7 @@ function getGeneratedTemplateContext(
136148
projectName: context.projectName,
137149
typescript: context.typescript,
138150
tailwind: context.tailwind,
151+
blank: context.blank,
139152
js: context.js,
140153
jsx: context.jsx,
141154
fileRouter: context.fileRouter,
@@ -238,6 +251,28 @@ function getAddOnExclusive(exclusive: string): WorkerAddOnExclusive {
238251
}
239252
}
240253

254+
function getAddOnPartnerTier(tier: string): WorkerAddOnPartner['tier'] {
255+
switch (tier) {
256+
case 'gold':
257+
case 'silver':
258+
case 'bronze':
259+
return tier
260+
default:
261+
throw new Error(`Unsupported partner tier: ${tier}`)
262+
}
263+
}
264+
265+
function getAddOnPartner(
266+
partner: GeneratedAddOnPartner | undefined,
267+
): WorkerAddOnManifest['partner'] {
268+
if (!partner) return undefined
269+
270+
return {
271+
...partner,
272+
tier: getAddOnPartnerTier(partner.tier),
273+
}
274+
}
275+
241276
function getAddOnEnvFile(file: string | undefined): WorkerAddOnEnvVar['file'] {
242277
switch (file) {
243278
case undefined:
@@ -310,6 +345,8 @@ function getPackageAdditions(
310345
const normalizedPackageAdditions: WorkerAddOnPackageAdditions = {
311346
dependencies: getStringRecord(packageAdditions.dependencies),
312347
devDependencies: getStringRecord(packageAdditions.devDependencies),
348+
engines: getStringRecord(packageAdditions.engines),
349+
pnpm: packageAdditions.pnpm,
313350
scripts: getStringRecord(packageAdditions.scripts),
314351
}
315352

@@ -327,6 +364,7 @@ function getAddOnMetadata(
327364
exclusive: addOn.exclusive?.map(getAddOnExclusive),
328365
envVars: getAddOnEnvVars(addOn.envVars),
329366
options: getAddOnOptions(addOn.options),
367+
partner: getAddOnPartner(addOn.partner),
330368
packageAdditions: getPackageAdditions(addOn.packageAdditions),
331369
}
332370
}
@@ -340,6 +378,7 @@ function getAddOnManifest(addOn: GeneratedAddOnManifest): WorkerAddOnManifest {
340378
exclusive: addOn.exclusive?.map(getAddOnExclusive),
341379
envVars: getAddOnEnvVars(addOn.envVars),
342380
options: getAddOnOptions(addOn.options),
381+
partner: getAddOnPartner(addOn.partner),
343382
packageAdditions: getPackageAdditions(addOn.packageAdditions),
344383
}
345384
}
@@ -376,6 +415,12 @@ function loadAddOn(
376415
}
377416
}
378417

418+
function defineAddOnLoaders(
419+
loaders: Record<string, () => Promise<WorkerAddOnManifestModule>>,
420+
) {
421+
return loaders
422+
}
423+
379424
const frameworkLoaders: Record<
380425
string,
381426
() => Promise<WorkerFrameworkManifestModule>
@@ -388,7 +433,7 @@ const frameworkLoaders: Record<
388433
),
389434
}
390435

391-
const reactAddOnLoaders = {
436+
const reactAddOnLoaders = defineAddOnLoaders({
392437
ai: loadAddOn(() =>
393438
import('@tanstack/create/worker-manifest/frameworks/react/add-ons/ai'),
394439
),
@@ -512,9 +557,9 @@ const reactAddOnLoaders = {
512557
workos: loadAddOn(() =>
513558
import('@tanstack/create/worker-manifest/frameworks/react/add-ons/workos'),
514559
),
515-
} satisfies Record<string, () => Promise<WorkerAddOnManifestModule>>
560+
})
516561

517-
const solidAddOnLoaders = {
562+
const solidAddOnLoaders = defineAddOnLoaders({
518563
'better-auth': loadAddOn(() =>
519564
import(
520565
'@tanstack/create/worker-manifest/frameworks/solid/add-ons/better-auth'
@@ -571,7 +616,7 @@ const solidAddOnLoaders = {
571616
'@tanstack/create/worker-manifest/frameworks/solid/add-ons/tanstack-query'
572617
),
573618
),
574-
} satisfies Record<string, () => Promise<WorkerAddOnManifestModule>>
619+
})
575620

576621
const addOnLoaders: Record<
577622
string,

src/builder/templates.ts

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -46,18 +46,10 @@ export const TEMPLATES: Array<Template> = [
4646
{
4747
id: 'saas',
4848
name: 'SaaS Starter',
49-
description: 'Auth, database, monitoring',
49+
description: 'Auth, database, and UI',
5050
icon: Rocket,
5151
color: '#F97316', // orange
52-
features: [
53-
'cloudflare',
54-
'better-auth',
55-
'neon',
56-
'drizzle',
57-
'sentry',
58-
'shadcn',
59-
'form',
60-
],
52+
features: ['cloudflare', 'better-auth', 'prisma', 'shadcn', 'form'],
6153
},
6254
{
6355
id: 'ai-chat',
@@ -81,7 +73,7 @@ export const TEMPLATES: Array<Template> = [
8173
description: 'Content-driven site',
8274
icon: FileText,
8375
color: '#EC4899', // pink
84-
features: ['cloudflare', 'strapi', 'tanstack-query'],
76+
features: ['cloudflare', 'tanstack-query'],
8577
},
8678
{
8779
id: 'api-first',
@@ -97,7 +89,7 @@ export const TEMPLATES: Array<Template> = [
9789
description: 'Live, collaborative features',
9890
icon: Radio,
9991
color: '#EF4444', // red
100-
features: ['cloudflare', 'convex', 'tanstack-query'],
92+
features: ['cloudflare', 'db', 'tanstack-query'],
10193
},
10294
{
10395
id: 'i18n',

0 commit comments

Comments
 (0)