To set up query caching in Retool: open the query editor → Advanced tab → toggle 'Cache the results' ON → set TTL in seconds. Start with slow aggregate queries (>500ms) and reference data tables. Use the Debug Panel Queries tab to confirm cache hits (look for 'served from cache' in the query metadata). Always pair caching with invalidateCache() calls after writes.
| Fact | Value |
|---|---|
| Tool | Retool |
| Difficulty | Advanced |
| Time required | 20-25 min |
| Compatibility | Retool Cloud and Self-hosted |
| Last updated | March 2026 |
A Practical Setup Walkthrough for Retool Query Caching
Caching in Retool is configured at the individual query level — each query independently decides whether to cache its results and for how long. There is no global cache policy, which means you need to evaluate each query and apply caching selectively.
This tutorial is the setup walkthrough companion to the 'How to use caching mechanisms in Retool' conceptual guide. It focuses on the practical decisions: which queries to cache, what TTL to choose, how to verify the cache is working, and how to plan your invalidation strategy.
The primary audience is Retool developers who know they have slow queries and want a concrete process for identifying cache candidates and configuring them correctly.
Prerequisites
- At least one Retool app with queries taking more than 300ms to execute
- Access to the query editor and Advanced settings tab
- Understanding of your data's change frequency (how often does the underlying data update?)
- Familiarity with the Debug Panel in Retool
Step-by-step guide
Identify cache candidates using Debug Panel timing
Before enabling caching, identify which queries are slowest using the Debug Panel. Click the bug icon to open the Debug Panel. Switch to the Queries tab. Run your app and observe query execution times in the waterfall. Queries taking more than 300ms that run frequently are the best cache candidates. Sort the list by duration — the longest-running queries at the top of the list are your highest-impact cache opportunities.
Expected result: List of queries sorted by execution time. Queries over 300ms are identified as cache candidates.
Assess data change frequency for each candidate
For each slow query identified, ask: 'How often does this data change, and how stale is too stale?' Create a simple TTL selection guide: data that changes real-time (order status, inventory) → no cache. Data that changes hourly (daily aggregates, reports) → 5-15 minute TTL. Data that changes daily (monthly summaries, customer stats) → 1-hour TTL. Reference data (lookup tables, country lists) → 24-hour TTL. Match the TTL to the acceptable staleness window for your business use case.
Expected result: Each candidate query has an assessed TTL value based on data change frequency.
Configure caching in the query Advanced tab
Open the slow query identified in Step 1. Click the 'Advanced' tab in the query editor. Scroll to find 'Cache the results' toggle — enable it. In the 'Cache TTL (seconds)' field, enter the TTL you determined in Step 2. For a daily summary query, enter 300 (5 minutes). For a reference data query, enter 3600 (1 hour). Save the query. The cache takes effect on the next run — the first run after enabling caching will always execute against the database and populate the cache.
1-- Example query with caching enabled2-- Query name: getProductCatalog3-- Advanced tab: Cache the results = ON, TTL = 3600 (1 hour)45SELECT6 id,7 name,8 sku,9 category,10 unit_price,11 is_active12FROM products13WHERE is_active = true14ORDER BY category, name;15-- This query rarely changes (product catalog updates are infrequent)16-- 1-hour cache drastically reduces load without meaningful stalenessExpected result: Caching is configured on the query. Next run populates the cache; subsequent runs within TTL are served from cache.
Verify cache is working using Debug Panel
Run your app again. Open the Debug Panel → Queries tab. Find your cached query in the list. After the first run (which populates the cache), trigger the query again. Observe that the second execution is near-instant (< 10ms). In the query detail, you should see metadata indicating 'served from cache'. You can also check programmatically with {{ queryName.servedFromCache }} — it returns true when the result came from cache.
Expected result: Second and subsequent query runs within the TTL window complete in under 10ms.
Set up cache invalidation for write operations
Identify all write queries (INSERT, UPDATE, DELETE) that affect the same data as your cached queries. For each write query, add cache invalidation to its success handler. The cleanest approach is a dedicated JS Query that runs all invalidations and refreshes after any write. Wire this query to the 'On success' event handler of each write query.
1// JS Query: invalidateDashboardCache2// Triggered by write operation success events3// Clears and refreshes all related cached queries45await Promise.all([6 getProductCatalog.invalidateCache(),7 getDailySummary.invalidateCache(),8 getCategoryStats.invalidateCache(),9]);1011// Immediately re-populate cache with fresh data12await Promise.all([13 getProductCatalog.trigger(),14 getDailySummary.trigger(),15 getCategoryStats.trigger(),16]);1718utils.showNotification({19 title: 'Saved and refreshed',20 notificationType: 'success',21});Expected result: After any write operation, cached queries are invalidated and immediately re-run to populate fresh cache entries.
Monitor cache effectiveness over time
Review the Debug Panel Performance tab weekly to confirm caching is reducing query execution times. If a query's average execution time is consistently low after enabling caching, the cache is working. If it's still slow, check whether the cache key is changing too frequently (different parameter values creating many unique cache entries) or whether the TTL is set too short. Adjust TTL values based on observed usage patterns.
Expected result: Dashboard shows reduced average query execution times. Database load decreases as cache hit rate increases.
Complete working example
1// JS Query: invalidateDashboardCache2// Use as the 'On success' handler for all write queries3// Invalidates and refreshes all dashboard cached queries45// Define which cached queries need invalidation6const cachedQueries = [7 { query: getProductCatalog, name: 'Product catalog' },8 { query: getDailySummary, name: 'Daily summary' },9 { query: getCategoryStats, name: 'Category stats' },10];1112try {13 // Step 1: Invalidate all cached entries simultaneously14 await Promise.all(cachedQueries.map(({ query }) => query.invalidateCache()));1516 // Step 2: Re-run all queries to warm up the cache17 await Promise.all(cachedQueries.map(({ query }) => query.trigger()));1819 utils.showNotification({20 title: 'Dashboard refreshed',21 description: `${cachedQueries.length} cached queries updated.`,22 notificationType: 'success',23 duration: 3,24 });25} catch (err) {26 utils.showNotification({27 title: 'Cache refresh failed',28 description: err.message,29 notificationType: 'error',30 });31}Common mistakes
Why it's a problem: Caching a query with user-specific parameters (like {{ retoolContext.currentUser.email }}) expecting per-user caches
How to avoid: Retool uses a single shared cache — different users with the same parameter values share a cache entry. Only cache queries returning data that should be identical for all users.
Why it's a problem: Enabling caching without planning cache invalidation, leading to stale data after writes
How to avoid: For every cached read query, identify all write queries that modify the same data, and add invalidateCache() calls to those write queries' success handlers.
Why it's a problem: Setting TTL to 0 or 1 second thinking this creates a 'minimal' cache
How to avoid: A TTL of 0 or 1 second effectively disables caching since it expires almost immediately. Either use a meaningful TTL (minimum 60 seconds) or disable caching entirely.
Best practices
- Start with your 5 slowest queries and enable caching only on those — don't cache everything blindly
- Choose TTL values conservatively: shorter TTLs are safer, longer TTLs give more performance benefit
- Create a central 'invalidateDashboardCache' JS Query that handles all cache invalidations after writes
- Document which queries are cached and their TTLs in the query description field for team awareness
- Test cache behavior in your staging environment before enabling in production
- Re-evaluate cache TTLs quarterly — data change patterns shift as applications evolve
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I have these Retool queries and need to determine appropriate caching TTLs: (1) getProductList — 2.5 second query returning 500 products that rarely change, (2) getDailyRevenue — 1.8 second aggregate query that needs to be accurate within 10 minutes, (3) getOrderStatus — real-time order tracking that must always be current, (4) getCountryList — static country reference data. For each query, recommend a TTL and explain the reasoning. Also show how to write a JS Query that invalidates all cached queries after a write operation.
Set up Retool query caching: Enable 'Cache the results' on getProductList (TTL 3600), getDailyRevenue (TTL 600), getCountryList (TTL 86400). Do NOT cache getOrderStatus. Write the invalidateDashboardCache JS Query using Promise.all([getProductList.invalidateCache(), getDailyRevenue.invalidateCache()]) followed by re-triggering. Show how to wire this to updateOrder query's 'On success' event.
Frequently asked questions
Is there a way to see all cached queries in a Retool app in one place?
There is no central cache management UI in Retool. You need to check each query individually in its Advanced tab. For larger teams, document cached queries in a shared resource (Notion, Confluence) and include the TTL and invalidation strategy for each.
Does caching affect query execution in preview mode vs published apps?
Caching works in both preview and published modes. However, the cache is stored separately — a cache populated in preview mode does not affect the published app's cache. This is intentional, allowing you to test cache behavior safely.
Can I programmatically warm up the cache on page load for all cached queries?
Yes — set all your cached queries to 'Run on page load'. On first page load, they execute against the database and populate the cache. Subsequent users who load the same page within the TTL window receive cached results immediately. This is the standard cache warming pattern in Retool.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation