Performance
Optimize your Typesense Search Plugin for maximum performance and scalability.
Built-in Caching
The plugin includes automatic caching for search results:
Cache Configuration
// 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:
curl "http://localhost:3000/api/search/health"Response includes cache statistics:
{
"cache": {
"maxSize": 1000,
"size": 45,
"hitRate": 0.85
}
}Search Optimization
Search Parameters
The plugin supports these performance-related search parameters:
// 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:
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:
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:
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:
<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:
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:
<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:
# 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:
# 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:
<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:
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
// Use only essential search fields
searchFields: ['title', 'content'] // Not all fields
// Limit facet fields
facetFields: ['category', 'status'] // Not too many2. Use Pagination
// 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
// 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 minute4. Optimize Typesense Settings
// 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
// Clear cache when needed (via health endpoint)
// The plugin automatically manages cache cleanup
// No manual cache management neededTroubleshooting Performance Issues
Slow Search Queries
- Check Typesense Performance: Monitor Typesense server metrics
- Optimize Search Fields: Reduce the number of search fields
- Use Pagination: Limit results per page
- Check Cache Hit Rate: Ensure caching is working effectively
High Memory Usage
- Reduce Cache Size: Lower
maxSizein cache settings - Reduce TTL: Lower cache TTL to free memory faster
- Monitor Cache Stats: Use health check to monitor cache usage
Connection Issues
- Check Typesense Nodes: Ensure all nodes are accessible
- Adjust Timeouts: Increase
connectionTimeoutSecondsif needed - Check Retry Settings: Adjust
numRetriesandretryIntervalSeconds
Next Steps
- Troubleshooting - Fix performance issues
- API Reference - Advanced search features
- Customization - Customize for your needs