Global variables in Retool persist across all pages in a multipage app. Create them in the Globals panel, set values with global.setValue('varName', value) in a JS Query, and read them anywhere with {{ global.varName }}. Unlike temporary state variables, globals survive page navigation for the duration of the user session.
| Fact | Value |
|---|---|
| Tool | Retool |
| Difficulty | Beginner |
| Time required | 10-15 min |
| Compatibility | Retool Cloud and Self-hosted |
| Last updated | March 2026 |
Cross-Page State with Global Variables
Global variables in Retool allow you to store data that is accessible from any page in a multipage application. This is fundamentally different from temporary state variables, which are scoped to a single page and reset on navigation.
A common use case is storing the currently selected record (e.g., a customer ID) on one page so that a detail page can query for it without relying on URL parameters. Another use case is tracking the user's workflow progress across a wizard-style app that spans multiple pages.
This tutorial covers creating global variables, setting their initial values, updating them from JS Queries, and reading them in component bindings and subsequent queries.
Prerequisites
- A Retool account (Cloud or Self-hosted)
- A multipage Retool app (or a single-page app to understand the concept)
- Basic familiarity with the Retool editor and JS Queries
- Understanding of the difference between the Code panel and the Inspector panel
Step-by-step guide
Open the Globals panel in the left sidebar
In the Retool editor, click the left sidebar and locate the Globals tab (it looks like a globe icon). This panel lists all global variables defined for the current app. If you are working in a single-page app, you will not see Globals — global variables only appear in multipage apps. If you do not have a multipage app, go to the app settings and enable multiple pages first.
Expected result: The Globals panel is visible and shows an empty list or existing global variables.
Create a new global variable
In the Globals panel, click the + button to add a new global variable. Give it a descriptive name such as selectedCustomerId. Set the Default value — this can be an empty string, null, 0, or any JSON-serializable value. The default value is what the variable holds when the app first loads, before any JS Query has set it.
Expected result: A new global variable named selectedCustomerId appears in the Globals panel with the default value you specified.
Set the global variable from a JS Query
Create a new JS Query (click + in the Code panel → JavaScript). To update the global variable, call global.setValue() and await the result. The method signature is: await global.setValue('varName', newValue). Note that setValue is asynchronous — if you need to read the value immediately after setting it, you must await the call or read from a local variable instead of from global.varName right away.
1// In a JS Query named 'setSelectedCustomer'2// Called from a Table row click event handler3const selectedRow = table1.selectedRow;4const customerId = selectedRow.data.id;56// setValue is async — always await it7await global.setValue('selectedCustomerId', customerId);89// Now navigate to the detail page10utils.openPage('CustomerDetail');Expected result: The global variable selectedCustomerId is updated to the selected row's ID, and the app navigates to the CustomerDetail page.
Read the global variable in a component or query
On any page in the app, you can reference a global variable using double curly braces: {{ global.selectedCustomerId }}. Use this in a query's WHERE clause, a Text component's value, or a conditional visibility expression. For example, in a SQL query on the CustomerDetail page, you would write WHERE id = {{ global.selectedCustomerId }} to fetch the selected customer's data.
1-- SQL Query on CustomerDetail page2SELECT *3FROM customers4WHERE id = {{ global.selectedCustomerId }}5LIMIT 1;Expected result: The query returns data for the customer whose ID was stored in the global variable.
Reset a global variable to its default
To reset a global variable to its default value, use global.resetValue('varName') from a JS Query. This is useful when a user logs out or navigates back to a list view and you want to clear the selection state. You can call this in an event handler on a Back button or in a page-load event.
1// JS Query: resetGlobalVars2await global.resetValue('selectedCustomerId');3// Variable is now back to its default value (e.g., null)Expected result: The global variable reverts to its default value. Components bound to it re-render with the default state.
Use global variables for multi-page wizard state
A powerful pattern for multi-page wizards is to accumulate form data into a global object variable. Create a global variable named wizardData with a default value of {}. On each page, merge new form fields into it using global.setValue(). On the final submission page, read the complete object and send it to your backend query.
1// Page 1 — save step 1 data2const existing = global.wizardData;3await global.setValue('wizardData', {4 ...existing,5 firstName: textInput1.value,6 lastName: textInput2.value7});8utils.openPage('WizardStep2');910// Final page — submit accumulated data11const formData = global.wizardData;12await submitNewUser.trigger({13 additionalScope: { payload: formData }14});Expected result: Each wizard page adds its data to the global variable, and the final page can access the full accumulated form data.
Complete working example
1// === Page 1: List page — set global on row click ===2// Event handler on table1 (Row click)3const selectedRow = table1.selectedRow;4if (!selectedRow || !selectedRow.data) {5 utils.showNotification({ title: 'No row selected', notificationType: 'warning' });6 return;7}89// Set the global variable (async — always await)10await global.setValue('selectedCustomerId', selectedRow.data.id);1112// Optionally store full row data for richer detail page13await global.setValue('selectedCustomerData', selectedRow.data);1415// Navigate to detail page16utils.openPage('CustomerDetail');1718// === CustomerDetail page — read global in SQL query ===19// Query: getCustomerDetail (runs on page load)20// SQL:21// SELECT c.*, o.count AS order_count22// FROM customers c23// LEFT JOIN (24// SELECT customer_id, COUNT(*) AS count FROM orders GROUP BY customer_id25// ) o ON o.customer_id = c.id26// WHERE c.id = {{ global.selectedCustomerId }}2728// === Reset on back button click ===29// JS Query: goBackToList30await global.resetValue('selectedCustomerId');31await global.resetValue('selectedCustomerData');32utils.openPage('CustomerList');Common mistakes
Why it's a problem: Reading global.varName immediately after calling setValue() without await
How to avoid: Always use await global.setValue('varName', value) and then read global.varName in a subsequent line or query. Without await, you are reading the stale value.
Why it's a problem: Creating global variables in a single-page app and wondering why they are not available
How to avoid: Global variables only exist in multipage apps. For single-page apps, use Temporary State (state variables) instead.
Why it's a problem: Storing large arrays or query result sets in global variables
How to avoid: Global variables are held in memory and serialized. Store only IDs or minimal selector state in globals, then re-query the full data on each page.
Why it's a problem: Forgetting that global variables reset to defaults on a fresh browser session
How to avoid: Do not rely on global variables for data that must survive page refresh. Use URL parameters or query the database for persistent state.
Best practices
- Always await global.setValue() calls — it is asynchronous and not reading the value immediately after setting without await will give you stale data.
- Set meaningful default values (e.g., null for IDs, {} for objects, [] for arrays) so components bound to globals render correctly on first load.
- Do not store sensitive data like passwords or tokens in global variables — they are accessible from any query or component in the app.
- Prefer global variables over URL parameters when passing complex objects between pages, since URL params only support strings.
- Use global.resetValue() in cleanup handlers (logout, back navigation) to prevent stale state leaking between user sessions.
- Keep global variable names descriptive and namespaced (e.g., selectedOrderId, filterState) to avoid confusion in large apps.
- Document your global variables in the app's description or a comment-only text component so teammates understand the data flow.
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I am building a multipage Retool app. I need to pass the selected row's ID from a Table component on Page 1 to a SQL query on Page 2. How do I use Retool global variables to do this? Please show me the JavaScript for setting the global variable on row click, how to reference it in a SQL query using {{ global.varName }}, and how to reset it when navigating back. Also explain the async nature of setValue().
In my Retool multipage app, write a JS Query that: (1) reads table1.selectedRow.data.id, (2) sets a global variable named selectedCustomerId using global.setValue(), (3) awaits the setValue call, (4) then calls utils.openPage('CustomerDetail'). Also show me how to use {{ global.selectedCustomerId }} in a SQL WHERE clause on the detail page.
Frequently asked questions
Do Retool global variables persist after a page refresh?
No. Global variables reset to their default values on every new browser session or page refresh. They only persist during active navigation within a single session. For data that must survive refresh, use URL parameters or query your database.
Can I use global variables in single-page Retool apps?
No. The Globals panel and global.setValue() are only available in multipage apps. For single-page apps, use Temporary State variables (state1.value and state1.setValue()) to manage cross-component state.
Is there a limit to how many global variables I can create in Retool?
Retool does not publish a hard limit on global variable count, but best practice is to keep the number small. Each global variable adds to the app definition size. Store IDs and minimal state rather than full query result sets.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation