Skip to main content
RapidDev - Software Development Agency
retool-tutorial

How to Set Up Data Caching in Retool

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.

What you'll learn

  • Enable 'Cache the results' in the query Advanced tab and set an appropriate TTL
  • Identify which queries benefit most from caching using Debug Panel timing
  • Select appropriate TTL values based on how frequently data changes
  • Monitor cache effectiveness using the Debug Panel's query execution tab
  • Build a cache invalidation strategy that integrates with your write operations
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Advanced7 min read20-25 minRetool Cloud and Self-hostedLast updated March 2026RapidDev Engineering Team
TL;DR

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.

Quick facts about this guide
FactValue
ToolRetool
DifficultyAdvanced
Time required20-25 min
CompatibilityRetool Cloud and Self-hosted
Last updatedMarch 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

1

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.

2

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.

3

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.

typescript
1-- Example query with caching enabled
2-- Query name: getProductCatalog
3-- Advanced tab: Cache the results = ON, TTL = 3600 (1 hour)
4
5SELECT
6 id,
7 name,
8 sku,
9 category,
10 unit_price,
11 is_active
12FROM products
13WHERE is_active = true
14ORDER BY category, name;
15-- This query rarely changes (product catalog updates are infrequent)
16-- 1-hour cache drastically reduces load without meaningful staleness

Expected result: Caching is configured on the query. Next run populates the cache; subsequent runs within TTL are served from cache.

4

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.

5

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.

typescript
1// JS Query: invalidateDashboardCache
2// Triggered by write operation success events
3// Clears and refreshes all related cached queries
4
5await Promise.all([
6 getProductCatalog.invalidateCache(),
7 getDailySummary.invalidateCache(),
8 getCategoryStats.invalidateCache(),
9]);
10
11// Immediately re-populate cache with fresh data
12await Promise.all([
13 getProductCatalog.trigger(),
14 getDailySummary.trigger(),
15 getCategoryStats.trigger(),
16]);
17
18utils.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.

6

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

JS Query: invalidateDashboardCache
1// JS Query: invalidateDashboardCache
2// Use as the 'On success' handler for all write queries
3// Invalidates and refreshes all dashboard cached queries
4
5// Define which cached queries need invalidation
6const cachedQueries = [
7 { query: getProductCatalog, name: 'Product catalog' },
8 { query: getDailySummary, name: 'Daily summary' },
9 { query: getCategoryStats, name: 'Category stats' },
10];
11
12try {
13 // Step 1: Invalidate all cached entries simultaneously
14 await Promise.all(cachedQueries.map(({ query }) => query.invalidateCache()));
15
16 // Step 2: Re-run all queries to warm up the cache
17 await Promise.all(cachedQueries.map(({ query }) => query.trigger()));
18
19 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.

ChatGPT Prompt

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.

Retool Prompt

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.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Learning is great. Shipping is faster with help.

Our engineers have built 600+ apps on Retool and the tools around it. If your project needs to be live sooner than your learning curve allows — book a free consultation.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.