Skip to content

Commit d9ca28b

Browse files
Merge branch 'main' into plugins-again
2 parents 446f5e2 + 8f69047 commit d9ca28b

16 files changed

+330
-157
lines changed

AGENTS.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,3 +246,40 @@ For runtime testing and verification, developers should:
246246
### Summary Rule
247247

248248
**If depth does not improve comprehension, remove it.**
249+
250+
## Writing Style
251+
252+
### Avoid Emdashes
253+
254+
**Never use emdashes (—) in writing. They make content smell like AI-generated text.**
255+
256+
Use these alternatives instead:
257+
258+
- Commas for parenthetical phrases
259+
- Colons to introduce lists or explanations
260+
- Periods to break into separate sentences
261+
- Parentheses when appropriate
262+
263+
**Bad:**
264+
265+
```
266+
RSCs aren't about replacing client interactivity — they're about choosing where work happens.
267+
```
268+
269+
**Good:**
270+
271+
```
272+
RSCs aren't about replacing client interactivity. They're about choosing where work happens.
273+
```
274+
275+
**Bad:**
276+
277+
```
278+
Heavy dependencies — markdown parsers, syntax highlighters — stay on the server.
279+
```
280+
281+
**Good:**
282+
283+
```
284+
Heavy dependencies (markdown parsers, syntax highlighters) stay on the server.
285+
```

media/brand.sketch

9.78 MB
Binary file not shown.
152 KB
Loading
-302 KB
Binary file not shown.

src/blog/announcing-tanstack-start-v1.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ That page will stay current with the exact commands for the RC and the final 1.0
3737

3838
## Path to 1.0 stable
3939

40-
We plan to cut 1.0 shortly after collecting RC feedback. Expect a few small RC iterations; any breaking changes will be clearly documented. As we approach stable, only light polish remains—no major API shifts.
40+
We plan to cut 1.0 shortly after collecting RC feedback. Expect a few small RC iterations; any breaking changes will be clearly documented. As we approach stable, only light polish remains. No major API shifts.
4141

4242
> **Note:** React Server Components support is in active development and will land as a non-breaking v1.x addition.
4343
@@ -67,6 +67,6 @@ Their collaboration is a pivotal force driving the open web forward. Explore the
6767

6868
## Your feedback counts
6969

70-
This is the moment when your feedback matters most. Try the RC in a new or existing project and tell us what you think via the docs feedback links. If you hit an issue, the migration notes and examples in the docs will help—and we’ll be quick to respond.
70+
This is the moment when your feedback matters most. Try the RC in a new or existing project and tell us what you think via the docs feedback links. If you hit an issue, the migration notes and examples in the docs will help. And we’ll be quick to respond.
7171

7272
Thanks for building with us. Let’s ship 1.0, together.
Lines changed: 56 additions & 50 deletions
Large diffs are not rendered by default.

src/blog/netlify-partnership.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Netlify has earned its reputation as the ultimate deployment platform for modern
1818

1919
## Why Netlify?
2020

21-
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.
21+
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.
2222

2323
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:
2424

src/blog/search-params-are-state.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ authors:
77

88
![Search Params Are State Header](/blog-assets/search-params-are-state/search-params-are-state-header.jpg)
99

10-
## Search Params Are State Treat Them That Way
10+
## Search Params Are State . Treat Them That Way
1111

12-
Search params have been historically treated like second-class state. They're global, serializable, and shareable but in most apps, they’re still hacked together with string parsing, loose conventions, and brittle utils.
12+
Search params have been historically treated like second-class state. They're global, serializable, and shareable . but in most apps, they’re still hacked together with string parsing, loose conventions, and brittle utils.
1313

1414
Even something simple, like validating a `sort` param, quickly turns verbose:
1515

@@ -30,7 +30,7 @@ This works, but it’s manual and repetitive. There’s no inference, no connect
3030

3131
Even worse, `URLSearchParams` is string-only. It doesn’t support nested JSON, arrays (beyond naive comma-splitting), or type coercion. So unless your state is flat and simple, you’re going to hit walls fast.
3232

33-
That’s why we’re starting to see a rise in tools and proposals things like Nuqs, Next.js RFCs, and userland patterns aimed at making search params more type-safe and ergonomic. Most of these focus on improving _reading_ from the URL.
33+
That’s why we’re starting to see a rise in tools and proposals . things like Nuqs, Next.js RFCs, and userland patterns . aimed at making search params more type-safe and ergonomic. Most of these focus on improving _reading_ from the URL.
3434

3535
But almost none of them solve the deeper, harder problem: **writing** search params, safely and atomically, with full awareness of routing context.
3636

@@ -56,15 +56,15 @@ Constraint is what makes coordination possible. It’s what allows **non-local c
5656

5757
---
5858

59-
### Local Abstractions Can Help But They Don’t Coordinate
59+
### Local Abstractions Can Help . But They Don’t Coordinate
6060

61-
Tools like **Nuqs** are a great example of how local abstractions can improve the _ergonomics_ of search param handling. You get Zod-powered parsing, type inference, even writable APIs all scoped to a specific component or hook.
61+
Tools like **Nuqs** are a great example of how local abstractions can improve the _ergonomics_ of search param handling. You get Zod-powered parsing, type inference, even writable APIs . all scoped to a specific component or hook.
6262

63-
They make it easier to read and write search params **in isolation** and that’s valuable.
63+
They make it easier to read and write search params **in isolation** . and that’s valuable.
6464

6565
But they don’t solve the broader issue of **coordination**. You still end up with duplicated schemas, disjointed expectations, and no way to enforce consistency between routes or components. Defaults can conflict. Types can drift. And when routes evolve, nothing guarantees all the callers update with them.
6666

67-
That’s the real fragmentation problem and fixing it requires bringing search param schemas into the routing layer itself.
67+
That’s the real fragmentation problem . and fixing it requires bringing search param schemas into the routing layer itself.
6868

6969
---
7070

@@ -100,13 +100,13 @@ navigate({
100100
})
101101
```
102102

103-
It’s reducer-style, transactional, and integrates directly with the router’s reactivity model. Components only re-render when the specific search param they use changes not every time the URL mutates.
103+
It’s reducer-style, transactional, and integrates directly with the router’s reactivity model. Components only re-render when the specific search param they use changes . not every time the URL mutates.
104104

105105
---
106106

107107
### How TanStack Router Prevents Schema Fragmentation
108108

109-
When your search param logic lives in userland scattered across hooks, utils, and helpers it’s only a matter of time before you end up with **conflicting schemas**.
109+
When your search param logic lives in userland . scattered across hooks, utils, and helpers . it’s only a matter of time before you end up with **conflicting schemas**.
110110

111111
Maybe one component expects \`sort: 'asc' | 'desc'\`. Another adds a \`filter\`. A third assumes \`sort: 'desc'\` by default. None of them share a source of truth.
112112

@@ -117,7 +117,7 @@ This leads to:
117117
- Navigation that sets values others can’t parse
118118
- Broken deep linking and bugs you can’t trace
119119

120-
TanStack Router prevents this by tying schemas directly to your route definitions **hierarchically**.
120+
TanStack Router prevents this by tying schemas directly to your route definitions . **hierarchically**.
121121

122122
Parent routes can define shared search param validation. Child routes inherit that context, add to it, or extend it in type-safe ways. This makes it _impossible_ to accidentally create overlapping, incompatible schemas in different parts of your app.
123123

@@ -160,23 +160,23 @@ validateSearch: z.object({
160160
})
161161
```
162162

163-
This kind of enforcement makes nested routes composable _and_ safe a rare combo.
163+
This kind of enforcement makes nested routes composable _and_ safe . a rare combo.
164164

165165
---
166166

167167
### Built-In Discipline
168168

169169
The magic here is that you don’t need to teach your team to follow conventions. The route _owns_ the schema. Everyone just uses it. There’s no duplication. No drift. No silent bugs. No guessing.
170170

171-
When you bring validation, typing, and ownership into the router itself, you stop treating URLs like strings and start treating them like real state because that’s what they are.
171+
When you bring validation, typing, and ownership into the router itself, you stop treating URLs like strings and start treating them like real state . because that’s what they are.
172172

173173
---
174174

175175
### Search Params Are State
176176

177177
Most routing systems treat search params like an afterthought. Something you _can_ read, maybe parse, maybe stringify, but rarely something you can actually **trust**.
178178

179-
TanStack Router flips that on its head. It makes search params a core part of the routing contract validated, inferable, writable, and reactive.
179+
TanStack Router flips that on its head. It makes search params a core part of the routing contract . validated, inferable, writable, and reactive.
180180

181181
Because if you’re not treating search params like state, you’re going to keep leaking it, breaking it, and working around it.
182182

src/blog/tanstack-ai-alpha-2.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Our goals were simple: move away from monolithic adapters and their complexity,
1515

1616
## New Adapter Architecture
1717

18-
We wanted to support everything AI providers offer—image generation, video, audio, text-to-speech, transcription—without updating every adapter simultaneously.
18+
We wanted to support everything AI providers offer. Image generation, video, audio, text-to-speech, transcription. Without updating every adapter simultaneously.
1919

2020
We're a small team. Adding image support shouldn't mean extending `BaseAdapter`, updating 5+ provider implementations, ensuring per-model type safety for each, and combing through docs manually. That's a week per provider. Multiply that by 20 providers and 6 modalities.
2121

@@ -37,7 +37,7 @@ import { openaiText, openaiImage, openaiVideo } from '@tanstack/ai-openai'
3737

3838
**Incremental feature support.** Add image generation to OpenAI this week, Gemini next week, video for a third provider the week after. Smaller releases, same pace.
3939

40-
**Easier maintenance.** Our adapter abstraction had grown to 7 type generics with only text, summarization, and embeddings. Adding 6 more modalities would have exploded complexity. Now each adapter is focused3 generics max.
40+
**Easier maintenance.** Our adapter abstraction had grown to 7 type generics with only text, summarization, and embeddings. Adding 6 more modalities would have exploded complexity. Now each adapter is focused. 3 generics max.
4141

4242
**Better bundle size.** You control what you pull in. Want only text? Import `openaiText`. Want text and images? Import both. Your bundle, your choice.
4343

@@ -168,4 +168,4 @@ We're confident in this direction. We think you'll like it too.
168168

169169
<!-- ---
170170
171-
_Curious how we got here? Read [The `ai()` Function That Almost Was](/blog/tanstack-ai-the-ai-function-postmortem)a post-mortem on the API we loved, built, and had to kill._ -->
171+
_Curious how we got here? Read [The `ai()` Function That Almost Was](/blog/tanstack-ai-the-ai-function-postmortem). a post-mortem on the API we loved, built, and had to kill._ -->

src/blog/tanstack-ai-the-ai-function-postmortem.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ ai({
3636
})
3737
```
3838

39-
Simple. Single function. Powers everything AI-related. Clear naming—you're using AI. Types constrained to each adapter's capabilities. Pass image options to an image adapter, text options to a text adapter.
39+
Simple. Single function. Powers everything AI-related. Clear naming. You're using AI. Types constrained to each adapter's capabilities. Pass image options to an image adapter, text options to a text adapter.
4040

4141
Change models? Type errors if something's not supported. Change adapters? Type errors if something's not supported.
4242

@@ -54,7 +54,7 @@ The simplicity of `ai()` for end users hid enormous implementation complexity.
5454

5555
**Attempt 1: Function Overloads**
5656

57-
We tried using function overloads to constrain each adapter's options. Too many scenarios. The overloads resolved to wrong signatures—you could end up providing video options instead of image options. We got it to 99% working, but the 1% felt wrong and was a bigger hurdle than you'd think.
57+
We tried using function overloads to constrain each adapter's options. Too many scenarios. The overloads resolved to wrong signatures. You could end up providing video options instead of image options. We got it to 99% working, but the 1% felt wrong and was a bigger hurdle than you'd think.
5858

5959
Having 10+ overloads is cumbersome. Get the order wrong and it all falls apart. This would exponentially increase the difficulty of contributions and lowered our confidence in shipping stable releases.
6060

@@ -68,7 +68,7 @@ We'll take complexity on our side over forcing you to use `as` casts or `any` ty
6868

6969
### The aiOptions Nightmare
7070

71-
We added a `createXXXOptions` API`createTextOptions`, `createImageOptions`, etc. You can construct options as ready-made agents and pass them into functions, overriding what you need.
71+
We added a `createXXXOptions` API. `createTextOptions`, `createImageOptions`, etc. You can construct options as ready-made agents and pass them into functions, overriding what you need.
7272

7373
To match the theme, we called it `aiOptions`. It would constrain everything to the modality and provider:
7474

@@ -82,13 +82,13 @@ ai(opts)
8282

8383
Here's where we hit the wall.
8484

85-
When `aiOptions` returned readonly values, spreading into `ai()` worked. But `aiOptions` was loosely typed—you could pass anything in.
85+
When `aiOptions` returned readonly values, spreading into `ai()` worked. But `aiOptions` was loosely typed. You could pass anything in.
8686

8787
When we fixed `aiOptions` to accept only valid properties, the spread would cast the `ai()` function to `any`. Then it would accept anything.
8888

8989
We went in circles. Get one part working, break another. Fix that, break the first thing.
9090

91-
I believe it could have been done. Our approach was probably just wrong—some subtle bug in the system causing everything to break. But that proves the point: it was too complex to wrap your head around and find the root cause. Any fix would have to propagate through all the adapters. Very costly.
91+
I believe it could have been done. Our approach was probably just wrong. Some subtle bug in the system causing everything to break. But that proves the point: it was too complex to wrap your head around and find the root cause. Any fix would have to propagate through all the adapters. Very costly.
9292

9393
We spent almost a week trying to get this API to work perfectly. We couldn't. Maybe another week would have done it. But then what? How would we fix bugs in this brittle type system? How would we find root causes?
9494

@@ -98,7 +98,7 @@ Even if we'd gotten it working, there was another problem.
9898

9999
We'd just split our adapters into smaller pieces so bundlers could tree-shake what you don't use. Then we put all that complexity right back into `ai()`.
100100

101-
We don't want to be the lodash of AI librariesbundling everything you don't use and calling it a day. If a huge adapter that bundles everything is not okay, a single function that does the same thing is definitely not okay.
101+
We don't want to be the lodash of AI libraries, bundling everything you don't use and calling it a day. If a huge adapter that bundles everything is not okay, a single function that does the same thing is definitely not okay.
102102

103103
## The Warnings We Missed
104104

@@ -112,7 +112,7 @@ The warning sign we missed? LLMs couldn't reliably generate code for this API.
112112

113113
Think about that. We're building tools for AI, and AI couldn't figure out how to use them. That should have been a massive clue that humans wouldn't reliably write to this API unaided either.
114114

115-
LLMs like function names that indicate what the thing does. `ai()`—who knows? `generateImage()`—crystal clear.
115+
LLMs like function names that indicate what the thing does. `ai()`? Who knows. `generateImage()`? Crystal clear.
116116

117117
When we finally asked the LLMs directly what they thought of the API, they were 4-0 against `ai()` and for the more descriptive approach we ended up with.
118118

@@ -147,7 +147,7 @@ adapter.image('model')
147147
adapter.text('model')
148148
```
149149

150-
Looks nicer. Feels more unified. Same problemstill bundles everything.
150+
Looks nicer. Feels more unified. Same problem: still bundles everything.
151151

152152
We could have done custom bundling in TanStack Start to strip unused parts, but we don't want to force you to use our framework for the best experience. This library is for the web ecosystem, not just TanStack users.
153153

0 commit comments

Comments
 (0)