Best Practices: Performance
When to Use
AJAX requests are slow, database queries are inefficient, or large operations cause timeouts.
Performance Optimization Strategies
Performance Optimization Strategies:
- Minimize DOM Updates
- Return smallest possible element, not entire form
- Use HtmlCommand instead of ReplaceCommand when wrapper unchanged
-
Batch multiple updates into single AJAX response
-
Database Optimization
- Always use
range(0, N)to limit query results - Load only needed fields with
loadMultiple()instead of full entities - Use
accessCheck(TRUE)to leverage query access caching -
Index custom fields used in AJAX queries
-
Batch Processing
- Use Batch API for operations processing >100 items
- Set progress indicators for operations >2 seconds
-
Break large operations into chunks to prevent timeouts
-
Caching
- Use CacheableAjaxResponse for cacheable content
- Configure proper cache contexts (user.permissions, languages, etc.)
- Add cache tags for automatic invalidation
-
Set realistic max-age (match content update frequency)
-
Asset Optimization
- Aggregate JavaScript/CSS in production
- Use
#attachedlibraries instead of AddJsCommand/AddCssCommand - Lazy load libraries only when needed
- Minimize third-party dependencies
Performance Thresholds
Performance Thresholds:
| Operation Type | Target Time | Action if Exceeded |
|---|---|---|
| Simple form field update | <200ms | Optimize query, reduce DOM update size |
| Autocomplete query | <500ms | Add result limit, index search fields |
| File upload | <5s for 2MB | Use progress bar, increase PHP limits |
| Batch operation | <30s total | Use Batch API with progress tracking |
Pattern
// 1. Return smallest element
public function ajaxCallback(array &$form, FormStateInterface $form_state) {
return $form['subcategory']; // NOT return $form
}
// 2. Always limit query results
$nids = $this->entityTypeManager->getStorage('node')->getQuery()
->condition('type', 'article')
->range(0, 50)
->accessCheck(TRUE)
->execute();
// 3. Use Batch API for large operations (>100 items / >30 seconds)
public function processBatch(array &$form, FormStateInterface $form_state) {
$batch = [
'operations' => [[[$this, 'processBatchOp'], [range(0, 99)]]],
'finished' => [$this, 'batchFinished'],
];
batch_set($batch);
return batch_process();
}
// 4. Use #attached instead of AddCssCommand/AddJsCommand
$build['#attached']['library'][] = 'my_module/dynamic-feature';
// 5. Progress indicator for slow operations
$form['trigger']['#ajax']['progress'] = [
'type' => 'bar',
'url' => Url::fromRoute('my_module.batch_progress')->toString(),
'interval' => 1000,
];
See Also
- ← Previous: Best Practices: Security | Next: Best Practices: Development Standards
- Performance Optimization
- Response Caching
- Reference: Database performance best practices