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

How to Secure API Keys in Retool

Never put API keys directly in Retool queries or component values — they will be visible in the app definition and network requests. Instead, store keys as environment/configuration variables (Settings → Configuration Variables) or as resource credentials. Access them in queries via {{ retoolContext.configVars.API_KEY }} or through the encrypted resource connection. Mark them as secret to prevent exposure in the UI.

What you'll learn

  • How to store API keys in Retool's environment/configuration variables (never in app code)
  • How to configure resource-level credentials that are encrypted at rest
  • The difference between secret and non-secret configuration variables
  • How to access configuration variables in queries using retoolContext.configVars.NAME
  • How to audit and rotate API keys without breaking existing apps
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate8 min read15-20 minRetool Cloud and Self-hostedLast updated March 2026RapidDev Engineering Team
TL;DR

Never put API keys directly in Retool queries or component values — they will be visible in the app definition and network requests. Instead, store keys as environment/configuration variables (Settings → Configuration Variables) or as resource credentials. Access them in queries via {{ retoolContext.configVars.API_KEY }} or through the encrypted resource connection. Mark them as secret to prevent exposure in the UI.

Quick facts about this guide
FactValue
ToolRetool
DifficultyIntermediate
Time required15-20 min
CompatibilityRetool Cloud and Self-hosted
Last updatedMarch 2026

Protecting Secrets and Credentials in Retool

API keys and credentials embedded directly in Retool queries, component values, or JavaScript code are a security risk. They can be viewed by anyone with edit access to the app, appear in network request logs, and get committed to source control when using Git sync.

Retool provides two secure storage mechanisms: Configuration Variables (formerly Environment Variables) stored in Settings, and Resource Credentials stored per resource. Both are encrypted at rest. Configuration Variables can be marked as 'secret' to prevent them from appearing in the Retool UI after initial entry. Resource Credentials are never exposed to the frontend.

This tutorial covers creating configuration variables, accessing them in queries, marking them as secrets, and the best practices for API key lifecycle management.

Prerequisites

  • Admin access to a Retool organization (required to create configuration variables)
  • An API key you need to store securely
  • Basic understanding of Retool resources and queries
  • Retool Cloud or Self-hosted instance

Step-by-step guide

1

Navigate to Settings → Configuration Variables

Log in as an Admin and go to Settings (gear icon top-right or your-retool.com/settings). Find 'Configuration Variables' in the Settings sidebar (may be labeled 'Environment Variables' in older Retool versions). This is where you define key-value pairs that are available across all apps in the organization. Keys are stored encrypted in Retool's backend.

Expected result: The Configuration Variables page shows a list of existing variables (if any) with a + button to add new ones.

2

Create a new configuration variable and mark it as secret

Click '+ New variable'. Enter a name following SCREAMING_SNAKE_CASE convention (e.g., STRIPE_SECRET_KEY, OPENAI_API_KEY, SENDGRID_API_KEY). Enter the value — the actual API key. Most critically: toggle the 'Secret' checkbox ON. Secret variables are write-only after initial creation — their value is never displayed in the UI again, preventing shoulder-surfing and accidental exposure in screenshots.

typescript
1// Configuration variable naming conventions:
2// STRIPE_SECRET_KEY → Payment API key
3// OPENAI_API_KEY → LLM API key
4// SENDGRID_API_KEY → Email API key
5// INTERNAL_API_TOKEN → Internal service token
6// DB_ENCRYPTION_KEY → For data encryption
7
8// Non-secret variables (safe to display in UI):
9// STRIPE_PUBLISHABLE_KEY → Public key, OK to show
10// APP_VERSION → Version string
11// SUPPORT_EMAIL → Email address

Expected result: The variable is created and stored. If marked secret, its value shows as '••••••' immediately after saving and cannot be viewed again — only overwritten.

3

Access configuration variables in queries

In any SQL or REST query, reference configuration variables using the retoolContext.configVars object. The syntax is {{ retoolContext.configVars.VARIABLE_NAME }}. For REST API queries, use this in the header value, URL, or body fields. For JS Queries, access the same object without {{ }} delimiters.

typescript
1// REST API query headers (e.g., Stripe API call):
2// Header: Authorization
3// Value: Bearer {{ retoolContext.configVars.STRIPE_SECRET_KEY }}
4
5// REST API query URL with config var:
6// https://api.example.com/v1/endpoint?token={{ retoolContext.configVars.API_TOKEN }}
7
8// In a JS Query (no {{ }} needed):
9const apiKey = retoolContext.configVars.OPENAI_API_KEY;
10const response = await fetch('https://api.openai.com/v1/chat/completions', {
11 method: 'POST',
12 headers: {
13 'Authorization': `Bearer ${apiKey}`,
14 'Content-Type': 'application/json'
15 },
16 body: JSON.stringify({ model: 'gpt-4', messages: [...] })
17});
18// NOTE: This makes a direct frontend fetch. For server-side calls,
19// use a resource query instead (resource handles auth server-side)

Expected result: The query sends requests with the API key from the configuration variable, not a hardcoded value.

4

Store credentials in resource connections for server-side security

The most secure option for API keys is to configure them in a Retool Resource connection (Settings → Resources). When you create a REST API or GraphQL resource, you enter the base URL and auth credentials (API key, OAuth tokens, etc.) in the resource configuration. These credentials are stored encrypted, never sent to the browser, and injected server-side into requests by Retool's backend. This is stronger than configuration variables because the key never reaches the client.

Expected result: Queries using the resource automatically include the configured credentials without any key appearing in the browser's network tab.

5

Set per-environment values for configuration variables

On Business and Enterprise plans, configuration variables can have different values per environment (staging vs production). Click on a configuration variable and set different values for each environment. This lets you use a test API key in staging and a live key in production — accessed via the same {{ retoolContext.configVars.STRIPE_SECRET_KEY }} reference, with Retool injecting the correct value based on the current environment.

typescript
1// Same variable name, different per-environment values:
2// STRIPE_SECRET_KEY:
3// staging → sk_test_xxxxxxxx
4// production → sk_live_xxxxxxxx
5
6// Query reference stays the same across environments:
7// Header: Authorization
8// Value: Bearer {{ retoolContext.configVars.STRIPE_SECRET_KEY }}
9
10// Check current environment in app logic:
11// {{ retoolContext.environment }}
12// → 'staging' or 'production'

Expected result: The same query uses the test key in staging and the live key in production without any code changes.

6

Audit and rotate API keys safely

When rotating an API key, follow this process: create the new key with your API provider, go to Settings → Configuration Variables, find the variable, and click Edit to update its value. Apps that use the variable immediately start using the new key — no app changes or republishing required. If you use resource-level auth, edit the resource's credential settings instead.

Expected result: The new API key is in effect for all apps using the variable immediately. The old key can now be safely revoked.

Complete working example

REST API Resource + JS Query: secureApiCall
1// === APPROACH 1: Resource-level credentials (most secure) ===
2// Configure in Settings → Resources → Create REST API resource:
3// Base URL: https://api.stripe.com
4// Auth type: Bearer Token
5// Token: sk_live_xxxxxxxxxx (stored encrypted server-side)
6
7// Query: stripeGetCustomer
8// Resource: stripe_api (configured above)
9// URL: /v1/customers/{{ table1.selectedRow.data.stripe_customer_id }}
10// (Credentials injected server-side — never visible in browser)
11
12// === APPROACH 2: Configuration variable (safer than hardcoding) ===
13// Configuration variable: SENDGRID_API_KEY (secret)
14
15// JS Query: sendEmail
16try {
17 const endpoint = 'https://api.sendgrid.com/v3/mail/send';
18 const apiKey = retoolContext.configVars.SENDGRID_API_KEY;
19
20 if (!apiKey) {
21 throw new Error('SENDGRID_API_KEY not configured in Settings → Configuration Variables');
22 }
23
24 const payload = {
25 personalizations: [{ to: [{ email: emailInput.value }] }],
26 from: { email: retoolContext.configVars.SENDER_EMAIL || 'noreply@example.com' },
27 subject: subjectInput.value,
28 content: [{ type: 'text/plain', value: bodyInput.value }]
29 };
30
31 // NOTE: This runs in browser — use resource query for production
32 const response = await fetch(endpoint, {
33 method: 'POST',
34 headers: {
35 'Authorization': `Bearer ${apiKey}`,
36 'Content-Type': 'application/json'
37 },
38 body: JSON.stringify(payload)
39 });
40
41 if (!response.ok) {
42 const error = await response.json();
43 throw new Error(error.errors?.[0]?.message || 'Email send failed');
44 }
45
46 utils.showNotification({ title: 'Email sent', notificationType: 'success' });
47
48} catch (err) {
49 console.error('Email error:', err);
50 utils.showNotification({
51 title: 'Email failed',
52 description: err.message,
53 notificationType: 'error'
54 });
55}

Common mistakes

Why it's a problem: Putting API keys directly in a query's header or body fields as plain text

How to avoid: Move the key to Settings → Configuration Variables, mark it as secret, and reference it with {{ retoolContext.configVars.KEY_NAME }} in the query.

Why it's a problem: Using a configuration variable without marking it as secret, then sharing an app screenshot that reveals the key

How to avoid: Mark the toggle 'Secret' when creating configuration variables for any sensitive value. Secret variables show as '••••••' in all Retool UIs.

Why it's a problem: Calling external APIs directly in JS Queries with fetch() and exposing API keys in browser network requests

How to avoid: Configure the API as a Retool Resource with credentials entered in the resource settings. Resource auth is injected server-side by Retool, invisible to browser DevTools.

Why it's a problem: Storing configuration variables in different Retool environments but forgetting to set production values

How to avoid: After creating a configuration variable, check each environment tab (staging, production) and verify values are set. An unset production value will return undefined, causing query failures.

Best practices

  • Never hardcode API keys in query bodies, component values, or JS Queries — they will be visible in the app definition and to anyone with edit access.
  • Mark all API keys and tokens as 'Secret' in Configuration Variables — secret values are write-only and cannot be viewed after entry.
  • Prefer resource-level credential storage over configuration variables for any API that supports it — resource credentials are injected server-side and never reach the browser.
  • Use per-environment configuration variable values (Business+) to automatically use test keys in staging and live keys in production.
  • Rotate API keys on a regular schedule and immediately after any team member with Admin access leaves the organization.
  • Audit who has Admin access to Retool regularly — Admins can view and modify Configuration Variable values.
  • For self-hosted Retool, set a strong ENCRYPTION_KEY environment variable in your deployment — this encrypts all stored credentials at rest.

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

I am building a Retool app that needs to call the Stripe API and the OpenAI API. I know I should not hardcode API keys in my queries. Explain: (1) how to create secret configuration variables in Retool Settings, (2) how to reference them in REST API query headers using {{ retoolContext.configVars.KEY_NAME }}, (3) the difference between configuration variables and resource-level credentials and which is more secure, and (4) how to rotate keys without causing app downtime.

Retool Prompt

In my Retool app, I have a JS Query that calls the OpenAI API with a hardcoded API key. Help me: (1) move the key to a secret configuration variable named OPENAI_API_KEY, (2) update the JS Query to read the key using retoolContext.configVars.OPENAI_API_KEY, (3) add error handling if the configuration variable is not set, and (4) explain why using a Retool REST API resource would be even more secure.

Frequently asked questions

Can regular users (non-Admins) see secret configuration variable values in Retool?

No. Secret configuration variables are stored encrypted and their values are never displayed in the Retool UI after initial entry — not to Admins, not to Editors, not to Viewers. Even Admins can only overwrite the value, not read it. This is similar to how GitHub Actions secrets work.

Is it safe to use fetch() with an API key from retoolContext.configVars in a JS Query?

It is safer than hardcoding, but the API key is still sent from the browser and may appear in browser DevTools network tab. For true server-side security, configure the API as a Retool Resource — resource authentication is injected server-side by Retool's backend and never sent to the browser.

What happens to apps when I update a configuration variable value?

Apps immediately use the new value — no republishing or changes required. The variable is injected into queries at request time, not baked into the app definition. This is why configuration variables are the recommended way to manage keys that need rotation.

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.