Documentation
Framework
Version
Class References
Function References
Interface References
Type Alias References
Variable References

Tree-Shaking

Tree-Shaking & Bundle Optimization

TanStack AI is designed from the ground up for maximum tree-shakeability. The entire system—from activity functions to adapters—uses a functional, modular architecture that ensures you only bundle the code you actually use.

Design Philosophy

Instead of a monolithic API that includes everything, TanStack AI provides:

  • Individual activity functions - Import only the activities you need (chat, summarize, etc.)
  • Individual adapter functions - Import only the adapters you need (openaiText, openaiSummarize, etc.)
  • Functional API design - Pure functions that can be easily eliminated by bundlers
  • Separate modules - Each activity and adapter lives in its own module

This design means that if you only use chat with OpenAI, you won't bundle code for summarization, image generation, or other providers.

Activity Functions

Each AI activity is exported as a separate function from @tanstack/ai:

ts
// Import only the activities you need
import { chat } from '@tanstack/ai'              // Chat/text generation
import { summarize } from '@tanstack/ai'          // Summarization
import { generateImage } from '@tanstack/ai'      // Image generation
import { generateSpeech } from '@tanstack/ai'     // Text-to-speech
import { generateTranscription } from '@tanstack/ai' // Audio transcription
import { generateVideo } from '@tanstack/ai'       // Video generation
// Import only the activities you need
import { chat } from '@tanstack/ai'              // Chat/text generation
import { summarize } from '@tanstack/ai'          // Summarization
import { generateImage } from '@tanstack/ai'      // Image generation
import { generateSpeech } from '@tanstack/ai'     // Text-to-speech
import { generateTranscription } from '@tanstack/ai' // Audio transcription
import { generateVideo } from '@tanstack/ai'       // Video generation

Example: Chat Only

If you only need chat functionality:

ts
// Only chat code is bundled
import { chat } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'

const stream = chat({
  adapter: openaiText('gpt-4o'),
  messages: [{ role: 'user', content: 'Hello!' }],
})
// Only chat code is bundled
import { chat } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'

const stream = chat({
  adapter: openaiText('gpt-4o'),
  messages: [{ role: 'user', content: 'Hello!' }],
})

Your bundle will not include:

  • Summarization logic
  • Image generation logic
  • Other activity implementations

Adapter Functions

Each provider package exports individual adapter functions for each activity type:

OpenAI

ts
import {
  openaiText,       // Chat/text generation
  openaiSummarize,  // Summarization
  openaiImage,      // Image generation
  openaiSpeech,     // Text-to-speech
  openaiTranscription, // Audio transcription
  openaiVideo,      // Video generation
} from '@tanstack/ai-openai'
import {
  openaiText,       // Chat/text generation
  openaiSummarize,  // Summarization
  openaiImage,      // Image generation
  openaiSpeech,     // Text-to-speech
  openaiTranscription, // Audio transcription
  openaiVideo,      // Video generation
} from '@tanstack/ai-openai'

Anthropic

ts
import {
  anthropicText,       // Chat/text generation
  anthropicSummarize,  // Summarization
} from '@tanstack/ai-anthropic'
import {
  anthropicText,       // Chat/text generation
  anthropicSummarize,  // Summarization
} from '@tanstack/ai-anthropic'

Gemini

ts
import {
  geminiText,       // Chat/text generation
  geminiSummarize,  // Summarization
  geminiImage,      // Image generation
  geminiSpeech,     // Text-to-speech (experimental)
} from '@tanstack/ai-gemini'
import {
  geminiText,       // Chat/text generation
  geminiSummarize,  // Summarization
  geminiImage,      // Image generation
  geminiSpeech,     // Text-to-speech (experimental)
} from '@tanstack/ai-gemini'

Ollama

ts
import {
  ollamaText,       // Chat/text generation
  ollamaSummarize,  // Summarization
} from '@tanstack/ai-ollama'
import {
  ollamaText,       // Chat/text generation
  ollamaSummarize,  // Summarization
} from '@tanstack/ai-ollama'

Complete Example

Here's how the tree-shakeable design works in practice:

ts
// Only import what you need
import { chat } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'

// Chat generation - returns AsyncIterable<StreamChunk>
const chatResult = chat({
  adapter: openaiText('gpt-4o'),
  messages: [{ role: 'user', content: 'Hello!' }],
})

for await (const chunk of chatResult) {
  console.log(chunk)
}
// Only import what you need
import { chat } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'

// Chat generation - returns AsyncIterable<StreamChunk>
const chatResult = chat({
  adapter: openaiText('gpt-4o'),
  messages: [{ role: 'user', content: 'Hello!' }],
})

for await (const chunk of chatResult) {
  console.log(chunk)
}

What gets bundled:

  • chat function and its dependencies
  • openaiText adapter and its dependencies
  • ✅ Chat-specific streaming and tool handling logic

What doesn't get bundled:

  • summarize function
  • generateImage function
  • ❌ Other adapter implementations (Anthropic, Gemini, etc.)
  • ❌ Other activity implementations

Using Multiple Activities

If you need multiple activities, import only what you use:

ts
import { chat, summarize } from '@tanstack/ai'
import {
  openaiText,
  openaiSummarize
} from '@tanstack/ai-openai'

// Each activity is independent
const chatResult = chat({
  adapter: openaiText('gpt-4o'),
  messages: [{ role: 'user', content: 'Hello!' }],
})

const summarizeResult = await summarize({
  adapter: openaiSummarize('gpt-4o-mini'),
  text: 'Long text to summarize...',
})
import { chat, summarize } from '@tanstack/ai'
import {
  openaiText,
  openaiSummarize
} from '@tanstack/ai-openai'

// Each activity is independent
const chatResult = chat({
  adapter: openaiText('gpt-4o'),
  messages: [{ role: 'user', content: 'Hello!' }],
})

const summarizeResult = await summarize({
  adapter: openaiSummarize('gpt-4o-mini'),
  text: 'Long text to summarize...',
})

Each activity is in its own module, so bundlers can eliminate unused ones.

Type Safety

The tree-shakeable design doesn't sacrifice type safety. Each adapter provides full type safety for its supported models:

ts
import { openaiText, type OpenAIChatModel } from '@tanstack/ai-openai'

const adapter = openaiText()

// TypeScript knows the exact models supported
const model: OpenAIChatModel = 'gpt-4o' // ✓ Valid
const model2: OpenAIChatModel = 'invalid' // ✗ Type error
import { openaiText, type OpenAIChatModel } from '@tanstack/ai-openai'

const adapter = openaiText()

// TypeScript knows the exact models supported
const model: OpenAIChatModel = 'gpt-4o' // ✓ Valid
const model2: OpenAIChatModel = 'invalid' // ✗ Type error

Create Options Functions

The create___Options functions are also tree-shakeable:

ts
import {
  createChatOptions,
  createImageOptions
} from '@tanstack/ai'

// Only import what you need
const chatOptions = createChatOptions({
  adapter: openaiText('gpt-4o'),
})
import {
  createChatOptions,
  createImageOptions
} from '@tanstack/ai'

// Only import what you need
const chatOptions = createChatOptions({
  adapter: openaiText('gpt-4o'),
})

Bundle Size Benefits

The functional, modular design provides significant bundle size benefits:

Importing Everything (Less Efficient)

ts
// ❌ Importing more than needed
import * as ai from '@tanstack/ai'
import * as openai from '@tanstack/ai-openai'

// This bundles all exports from both packages
// ❌ Importing more than needed
import * as ai from '@tanstack/ai'
import * as openai from '@tanstack/ai-openai'

// This bundles all exports from both packages
ts
// ✅ Only what you use gets bundled
import { chat } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'

// You only get:
// - Chat activity implementation
// - OpenAI text adapter
// - Chat-specific dependencies
// ✅ Only what you use gets bundled
import { chat } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'

// You only get:
// - Chat activity implementation
// - OpenAI text adapter
// - Chat-specific dependencies

Real-World Impact

For a typical chat application:

  • Monolithic approach: ~200KB+ (all activities + all adapters)
  • Tree-shakeable approach: ~50KB (only chat + one adapter)

That's a 75% reduction in bundle size for most applications!

How It Works

The tree-shakeability is achieved through:

  1. ES Module exports - Each function is a named export, not a default export
  2. Separate modules - Each activity and adapter lives in its own file
  3. No side effects - Functions are pure and don't have module-level side effects
  4. Functional composition - Functions compose together, allowing dead code elimination
  5. Type-only imports - Type imports are stripped at build time

Modern bundlers (Vite, Webpack, Rollup, esbuild) can easily eliminate unused code because:

  • Functions are statically analyzable
  • No dynamic imports of unused code
  • No module-level side effects
  • Clear dependency graphs

Best Practices

  1. Import only what you need - Don't import entire namespaces
  2. Use specific adapter functions - Import openaiText not openai
  3. Separate activities by route - Different API routes can use different activities
  4. Lazy load when possible - Use dynamic imports for code-split routes
ts
// ✅ Good - Only imports chat
import { chat } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'

// ❌ Bad - Imports everything
import * as ai from '@tanstack/ai'
import * as openai from '@tanstack/ai-openai'
// ✅ Good - Only imports chat
import { chat } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'

// ❌ Bad - Imports everything
import * as ai from '@tanstack/ai'
import * as openai from '@tanstack/ai-openai'

Adapter Types

Each adapter type implements a specific interface:

  • ChatAdapter - Provides chatStream() method for streaming chat responses
  • SummarizeAdapter - Provides summarize() method for text summarization
  • ImageAdapter - Provides generateImage() method for image generation
  • TTSAdapter - Provides generateSpeech() method for text-to-speech
  • TranscriptionAdapter - Provides generateTranscription() method for audio transcription
  • VideoAdapter - Provides generateVideo() method for video generation

All adapters have a kind property that indicates their type:

ts
const chatAdapter = openaiText()
console.log(chatAdapter.kind) // 'text'

const summarizeAdapter = openaiSummarize()
console.log(summarizeAdapter.kind) // 'summarize'
const chatAdapter = openaiText()
console.log(chatAdapter.kind) // 'text'

const summarizeAdapter = openaiSummarize()
console.log(summarizeAdapter.kind) // 'summarize'

Summary

TanStack AI's tree-shakeable design means:

  • Smaller bundles - Only include code you actually use
  • Faster load times - Less JavaScript to download and parse
  • Better performance - Less code means faster execution
  • Type safety - Full TypeScript support without runtime overhead
  • Flexibility - Mix and match activities and adapters as needed

The functional, modular architecture ensures that modern bundlers can eliminate unused code effectively, resulting in optimal bundle sizes for your application.