Skip to content

Performance ​

Optimize your Typesense Search Plugin for maximum performance and scalability.

Built-in Caching ​

The plugin includes automatic caching for search results:

Cache Configuration ​

typescript
// Configure cache settings in plugin options
typesenseSearch({
  settings: {
    cache: {
      maxSize: 1000, // Maximum number of cached entries
      ttl: 300000, // Time-to-live in milliseconds (5 minutes)
    },
  },
  // ... other config
})

Cache Behavior ​

  • Automatic: All search results are automatically cached
  • TTL: 5 minutes by default (300,000ms)
  • Max Size: 1000 entries by default
  • Cleanup: Expired entries are cleaned up every 10 minutes
  • Key Generation: Based on query, collection, and parameters

Cache Statistics ​

Monitor cache performance via the health check endpoint:

bash
curl "http://localhost:3000/api/search/health"

Response includes cache statistics:

json
{
  "cache": {
    "maxSize": 1000,
    "size": 45,
    "hitRate": 0.85
  }
}

Search Optimization ​

Search Parameters ​

The plugin supports these performance-related search parameters:

typescript
// Available search parameters
interface SearchParams {
  q: string // Search query (required)
  page?: number // Page number (1-based, default: 1)
  per_page?: number // Results per page (1-250, default: 10)
  sort_by?: string // Sort field and direction
  num_typos?: number // Typo tolerance (0-4, default: 0)
  snippet_threshold?: number // Snippet threshold (0-100, default: 30)
  typo_tokens_threshold?: number // Typo tokens threshold (default: 1)
  facets?: string[] // Facet fields
  filters?: Record<string, any> // Filter conditions
  highlight_fields?: string[] // Fields to highlight
}

Collection Configuration ​

Optimize collections for better performance:

typescript
collections: {
  posts: {
    enabled: true,
    searchFields: ['title', 'content', 'excerpt'], // Only essential fields
    facetFields: ['category', 'status'],           // Limit facets
    displayName: 'Blog Posts',
    icon: '📝'
  }
}

Initial Sync Performance ​

Control the initial data synchronization performance with sync limits:

typescript
settings: {
  defaultSyncLimit: 1000, // Default documents per page during initial sync
}

collections: {
  largeCollection: {
    enabled: true,
    searchFields: ['title', 'content'],
    syncLimit: 5000, // Higher limit for large collections (fewer API calls)
  },
  smallCollection: {
    enabled: true,
    searchFields: ['name'],
    // Uses defaultSyncLimit (1000) - sufficient for smaller collections
  },
}

Sync Limit Guidelines:

  • Small collections (< 1,000 docs): Default limit (1000) is sufficient
  • Medium collections (1,000-10,000 docs): Increase to 2000-3000
  • Large collections (> 10,000 docs): Increase to 5000+ to reduce API calls
  • Memory-constrained environments: Decrease limit to 500-1000

The plugin automatically paginates through all documents, so all data will be synced regardless of the limit. The limit only controls the page size for better performance.

Typesense Configuration ​

Optimize Typesense connection settings:

typescript
typesense: {
  apiKey: process.env.TYPESENSE_API_KEY,
  nodes: [
    {
      host: process.env.TYPESENSE_HOST,
      port: parseInt(process.env.TYPESENSE_PORT),
      protocol: 'https'
    }
  ],
  connectionTimeoutSeconds: 10,  // Connection timeout
  numRetries: 3,                // Retry attempts
  retryIntervalSeconds: 1       // Retry interval
}

React Component Performance ​

Debouncing ​

Use debouncing to reduce API calls:

tsx
<HeadlessSearchInput
  baseUrl="http://localhost:3000"
  collection="posts"
  debounceMs={300} // 300ms debounce
  minQueryLength={2} // Minimum query length
  perPage={10} // Limit results per page
/>

Memoization ​

Memoize expensive operations:

tsx
import React, { memo, useCallback, useMemo } from 'react'
import { HeadlessSearchInput } from 'typesense-search-plugin'

// Memoize result component
const SearchResult = memo(({ hit }: { hit: SearchResult }) => (
  <div className="result">
    <h3>{hit.document.title}</h3>
    <p>{hit.document.content}</p>
  </div>
))

// Memoize search handler
const SearchPage = () => {
  const handleResultClick = useCallback((result: SearchResult) => {
    console.log('Selected:', result.document)
  }, [])

  const searchConfig = useMemo(
    () => ({
      baseUrl: 'http://localhost:3000',
      debounceMs: 300,
      minQueryLength: 2,
      perPage: 10,
    }),
    [],
  )

  return (
    <HeadlessSearchInput
      {...searchConfig}
      collection="posts"
      onResultClick={handleResultClick}
      renderResult={(hit, index) => <SearchResult key={index} hit={hit} />}
    />
  )
}

Custom Rendering ​

Optimize rendering with custom components:

tsx
<HeadlessSearchInput
  baseUrl="http://localhost:3000"
  collection="posts"
  renderResult={(hit, index) => (
    <div key={hit.id} className="result">
      <h3>{hit.document.title}</h3>
      <p>{hit.document.excerpt}</p>
    </div>
  )}
  renderLoading={() => <div>Searching...</div>}
  renderNoResults={(query) => <div>No results for "{query}"</div>}
/>

Network Optimization ​

Request Optimization ​

The plugin automatically optimizes requests:

  • Parallel Search: Universal search queries all collections in parallel
  • Caching: Results are cached to avoid duplicate requests
  • Parameter Validation: Invalid parameters are rejected early
  • Connection Pooling: Typesense client handles connection pooling

Pagination ​

Use pagination for large result sets:

bash
# First page
curl "http://localhost:3000/api/search?q=typesense&page=1&per_page=20"

# Next page
curl "http://localhost:3000/api/search?q=typesense&page=2&per_page=20"

Monitoring Performance ​

Health Check ​

Monitor plugin health and performance:

bash
# Basic health check
curl "http://localhost:3000/api/search/health"

# Detailed health check
curl "http://localhost:3000/api/search/health/detailed"

Performance Metrics ​

Track search performance in your application:

tsx
<HeadlessSearchInput
  baseUrl="http://localhost:3000"
  collection="posts"
  onResults={(results) => {
    // Track search performance
    console.log(`Search completed in ${results.search_time_ms}ms`)
    console.log(`Found ${results.found} results`)

    // Send to analytics
    analytics.track('search_completed', {
      query: results.request_params.q,
      searchTime: results.search_time_ms,
      resultCount: results.found,
    })
  }}
  onError={(error) => {
    // Track search errors
    console.error('Search error:', error)
    analytics.track('search_error', { error })
  }}
/>

Scaling Considerations ​

Multiple Typesense Nodes ​

Configure multiple Typesense nodes for high availability:

typescript
typesense: {
  apiKey: process.env.TYPESENSE_API_KEY,
  nodes: [
    { host: 'typesense-1.example.com', port: 443, protocol: 'https' },
    { host: 'typesense-2.example.com', port: 443, protocol: 'https' },
    { host: 'typesense-3.example.com', port: 443, protocol: 'https' }
  ],
  connectionTimeoutSeconds: 5,
  numRetries: 3
}

Load Balancing ​

The Typesense client automatically handles load balancing across multiple nodes.

Best Practices ​

1. Optimize Search Fields ​

typescript
// Use only essential search fields
searchFields: ['title', 'content'] // Not all fields

// Limit facet fields
facetFields: ['category', 'status'] // Not too many

2. Use Pagination ​

typescript
// Implement pagination for large result sets
const searchWithPagination = async (query: string, page: number = 1) => {
  return await fetch(`/api/search?q=${query}&page=${page}&per_page=20`)
}

3. Monitor Performance ​

typescript
// Regular performance monitoring
setInterval(() => {
  fetch('/api/search/health')
    .then((res) => res.json())
    .then((data) => {
      console.log('Cache hit rate:', data.cache?.hitRate)
      console.log('Cache size:', data.cache?.size)
    })
}, 60000) // Every minute

4. Optimize Typesense Settings ​

typescript
// Use appropriate Typesense settings
const searchParameters = {
  num_typos: 1, // Allow some typos for better UX
  snippet_threshold: 30, // Reasonable snippet length
  typo_tokens_threshold: 1, // Token threshold
  per_page: 20, // Reasonable page size
}

5. Cache Management ​

typescript
// Clear cache when needed (via health endpoint)
// The plugin automatically manages cache cleanup
// No manual cache management needed

Troubleshooting Performance Issues ​

Slow Search Queries ​

  1. Check Typesense Performance: Monitor Typesense server metrics
  2. Optimize Search Fields: Reduce the number of search fields
  3. Use Pagination: Limit results per page
  4. Check Cache Hit Rate: Ensure caching is working effectively

High Memory Usage ​

  1. Reduce Cache Size: Lower maxSize in cache settings
  2. Reduce TTL: Lower cache TTL to free memory faster
  3. Monitor Cache Stats: Use health check to monitor cache usage

Connection Issues ​

  1. Check Typesense Nodes: Ensure all nodes are accessible
  2. Adjust Timeouts: Increase connectionTimeoutSeconds if needed
  3. Check Retry Settings: Adjust numRetries and retryIntervalSeconds

Next Steps ​

Released under the MIT License.