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

How to Use Global Variables in Retool

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.

What you'll learn

  • The difference between global variables and state variables in Retool
  • How to create and set global variables using global.setValue('name', value)
  • How to read global variable values with {{ global.varName }} in any component
  • How to share data across pages in a multipage Retool app
  • Common pitfalls when using global variables and how to avoid them
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner7 min read10-15 minRetool Cloud and Self-hostedLast updated March 2026RapidDev Engineering Team
TL;DR

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.

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

1

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.

2

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.

3

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.

typescript
1// In a JS Query named 'setSelectedCustomer'
2// Called from a Table row click event handler
3const selectedRow = table1.selectedRow;
4const customerId = selectedRow.data.id;
5
6// setValue is async — always await it
7await global.setValue('selectedCustomerId', customerId);
8
9// Now navigate to the detail page
10utils.openPage('CustomerDetail');

Expected result: The global variable selectedCustomerId is updated to the selected row's ID, and the app navigates to the CustomerDetail page.

4

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.

typescript
1-- SQL Query on CustomerDetail page
2SELECT *
3FROM customers
4WHERE id = {{ global.selectedCustomerId }}
5LIMIT 1;

Expected result: The query returns data for the customer whose ID was stored in the global variable.

5

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.

typescript
1// JS Query: resetGlobalVars
2await 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.

6

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.

typescript
1// Page 1 — save step 1 data
2const existing = global.wizardData;
3await global.setValue('wizardData', {
4 ...existing,
5 firstName: textInput1.value,
6 lastName: textInput2.value
7});
8utils.openPage('WizardStep2');
9
10// Final page — submit accumulated data
11const 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

JS Query: globalVariableWorkflow
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}
8
9// Set the global variable (async — always await)
10await global.setValue('selectedCustomerId', selectedRow.data.id);
11
12// Optionally store full row data for richer detail page
13await global.setValue('selectedCustomerData', selectedRow.data);
14
15// Navigate to detail page
16utils.openPage('CustomerDetail');
17
18// === CustomerDetail page — read global in SQL query ===
19// Query: getCustomerDetail (runs on page load)
20// SQL:
21// SELECT c.*, o.count AS order_count
22// FROM customers c
23// LEFT JOIN (
24// SELECT customer_id, COUNT(*) AS count FROM orders GROUP BY customer_id
25// ) o ON o.customer_id = c.id
26// WHERE c.id = {{ global.selectedCustomerId }}
27
28// === Reset on back button click ===
29// JS Query: goBackToList
30await 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.

ChatGPT Prompt

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().

Retool Prompt

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.

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.