# How to Deploy a Retool App to Production

- Tool: Retool
- Difficulty: Intermediate
- Time required: 20-30 min
- Compatibility: Retool Cloud and Self-hosted
- Last updated: March 2026

## TL;DR

Retool separates editing from production: editors work on the draft (current edit), and users always run the latest published release. To deploy, open the Release Manager (three-dot menu → Manage Releases or the Deploy button), create a new release, and publish it. Released apps can be rolled back instantly by activating a previous version. Before releasing, verify your resources point to production databases via the environment selector.

## Retool's Release and Deployment Model

Retool uses a draft/release model. When you edit an app, you're always modifying the current draft — this is not immediately visible to end users. Users run the most recently published release. This separation means you can make iterative changes and only push them to users when ready.

Publishing a release creates an immutable snapshot of the app at that point in time. If something breaks in production, you can roll back to the previous release in seconds. Retool stores a history of all published releases.

For apps connected to multiple environments (staging database for testing, production database for live users), the environment selector ensures queries run against the right backend at the right time.

This tutorial walks through the full deployment lifecycle: pre-release preparation, publishing, environment configuration, and rollback procedures.

## Before you start

- A Retool app that is ready to deploy (tested in editor and preview modes)
- Editor or Admin access to the Retool app
- Resources configured for both staging and production if using multiple environments
- User permissions set up for who should access the deployed app

## Step-by-step guide

### 1. Understand the draft vs. release model

Before deploying, understand how Retool's release system works. The current app you see when editing is the draft version. Users who open the app URL always run the most recent published release — they never see your draft edits in progress.

To see which version users are running: open the app → three-dot menu (top-right) → Manage Releases. You'll see a list of all published releases with timestamps and the currently active version marked. Any release can be made active with one click — this is your rollback mechanism.

**Expected result:** You understand the draft vs. released distinction and can navigate to the Release Manager.

### 2. Run the pre-release checklist

Before publishing, verify these items in the app:

1. Test all queries in Preview mode — not just in the editor canvas
2. Confirm queries use the correct production resource (not a dev/staging database)
3. Check user permissions: Settings → Permissions → verify which groups can view/edit the app
4. Remove any test data, console.log() statements in JS queries, and debug-only components
5. Verify error handling: queries should have On Error handlers, not just silent failures
6. Check the app URL — ensure it doesn't expose query results in the URL via `{{ currentUrl }}` leakage
7. If using environment variables, confirm production values are set correctly

```
// JS Query pre-release cleanup: remove console.log
// BEFORE (dev/debug):
console.log('Debug:', query1.data);
const result = processData(query1.data);
return result;

// AFTER (production-ready):
const result = processData(query1.data);
return result;

// Also ensure error handling is in place on queries:
// Inspector → Interaction → On Failure → Show notification
// 'Query failed: {{ error.message }}'
```

**Expected result:** App is tested in Preview mode with production resources and no debug artifacts remaining.

### 3. Configure the production environment

If your app has queries that connect to different databases depending on the environment, configure the environment before releasing. In the Retool editor, look for the Environment selector in the toolbar (it shows 'Staging' or 'Production' depending on your setup). Switch to Production and verify that all queries execute against the production resource.

For apps using `{{ retoolContext.environment }}` in query logic, also confirm that production-specific behavior (stricter rate limits, real API keys, real payment processing) is tested.

```
// Query logic that behaves differently by environment:
// SQL query with environment-conditional behavior:
-- This query runs in both environments
-- Retool selects the resource based on the environment switcher
SELECT * FROM orders WHERE status = 'pending'
LIMIT {{ retoolContext.environment === 'production' ? 100 : 10 }}

// JS Query environment check:
if (retoolContext.environment === 'production') {
  // Use real payment processor
  return await processRealPayment.trigger();
} else {
  // Use test mode
  return await processTestPayment.trigger();
}
```

**Expected result:** All queries run against production resources when the environment selector shows Production.

### 4. Publish a new release

When the app is ready, publish it:

1. Open the three-dot menu (⋮) in the top-right of the editor, OR click the 'Deploy' button
2. Select 'Manage Releases' (or the release dialog opens directly)
3. Click 'Create Release' (or 'Publish' depending on your Retool version)
4. Enter a release note describing what changed (e.g., 'Add export to CSV button', 'Fix: pagination bug on orders table')
5. Optionally, specify a version tag
6. Click Publish

The release is immediately active. Users opening the app URL will now run this version. Previous releases remain accessible in the Release Manager.

**Expected result:** The Release Manager shows the new release as the current active version with a green indicator.

### 5. Configure app sharing and permissions before releasing

Who can access the app URL? Configure this in Settings → Permissions → App Access. By default, only Retool users in your organization can access the app. For apps accessed by external users (e.g., customer portal, partner tool), configure public access or restricted email domains.

Key permission levels:
- Use: can run the app, cannot edit
- Edit: can modify the app (editor access)
- Own: can delete the app and manage permissions

Set the app's Access Level to All users (all org members) or specific Groups.

```
// Conditional UI based on user permissions:
// Show admin controls only to users in the 'Admin' group:
// Button component → Hidden property:
{{ !current_user.groups.includes('Admin') }}

// Show user's own records only:
// SQL query WHERE clause:
WHERE created_by = {{ current_user.email }}

// Check environment and permissions in one expression:
{{ retoolContext.environment === 'production' && current_user.groups.includes('Admin') }}
```

**Expected result:** App permissions are configured so the right users have access after deployment.

### 6. Roll back to a previous release

If a deployed release causes issues (a query breaks, the UI is broken for certain users, a critical bug slipped through), roll back instantly:

1. Open the three-dot menu → Manage Releases
2. Find the last known-good release in the list
3. Click 'Activate' or 'Set as Current'
4. The previous release becomes active immediately — no cache clearing or deployment pipeline needed

The broken release remains in the release history and is not deleted. You can investigate and fix the issue in the draft, then publish a new release when ready.

**Expected result:** The Release Manager shows the previous release as active, and users running the app now see the rolled-back version.

### 7. Set up Protected Apps for Enterprise deployment control (optional)

On Retool Enterprise plans, Protected Apps adds a required code review step before any release can be published to users. This is analogous to a pull request process for app changes.

Enable Protected Apps: Settings → Permissions → Protected Apps toggle. Once enabled, editors submit releases for approval, and designated reviewers must approve before the release goes live. This is valuable for apps handling financial transactions, medical data, or sensitive operations.

**Expected result:** Protected Apps is configured and all future releases require reviewer approval before activating.

## Complete code example

File: `JS Query: preDeploymentChecks`

```javascript
// JS Query: preDeploymentChecks
// Run this before publishing a release to catch common issues
// Returns a list of warnings

const warnings = [];
const errors = [];

// Check 1: Verify environment
if (retoolContext.environment !== 'production') {
  warnings.push('WARNING: App is in ' + retoolContext.environment + ' environment, not production');
}

// Check 2: Check for test/debug data in state variables (example)
// if (testModeVar.value === true) {
//   errors.push('ERROR: testModeVar is still set to true');
// }

// Check 3: Verify required config vars are set
const requiredVars = ['API_BASE_URL', 'STRIPE_KEY'];
// requiredVars.forEach(varName => {
//   if (!retoolContext.configVars[varName]) {
//     errors.push('ERROR: Config var ' + varName + ' is not set for this environment');
//   }
// });

// Output summary
if (errors.length > 0) {
  return {
    status: 'BLOCKED',
    message: 'Cannot deploy — critical errors found',
    errors,
    warnings
  };
}

return {
  status: warnings.length > 0 ? 'DEPLOY_WITH_WARNINGS' : 'READY_TO_DEPLOY',
  message: warnings.length > 0 ? 'Review warnings before deploying' : 'All checks passed',
  errors: [],
  warnings
};
```

## Common mistakes

- **Sharing the editor URL (ending in /editor) with end users instead of the app URL** — undefined Fix: Always share the production app URL without /editor. Editor URLs give users editing access and show the draft version. Find the correct share URL in the three-dot menu → Share App or from the app list in the Retool home page.
- **Publishing a release while the environment selector shows 'Staging', causing queries to run against the staging database for end users** — undefined Fix: Before releasing, switch the Environment selector to Production, test the app in Preview mode, then publish. The release captures the app configuration but not the environment selector state — users run the app against whichever resource is configured for their environment.
- **Not adding release notes, making it impossible to identify which release introduced a bug** — undefined Fix: Always write at least one sentence of release notes: 'Added CSV export to orders table' or 'Fixed: sorting bug on user list'. These appear in the Release Manager log and save significant time during incident investigation.

## Best practices

- Always test in Preview mode with the Production environment selected before publishing — the editor canvas can mask query/resource issues
- Write descriptive release notes for every deployment — they're your deployment log and invaluable for diagnosing production issues
- Configure rollback-ready releases: keep the last 3-5 stable releases active in the Release Manager so you can roll back instantly
- Use Protected Apps (Enterprise) or a peer review process for apps handling financial, medical, or security-sensitive data
- Never share the editor URL with end users — always share the app URL which serves the released version
- Set app permissions before releasing: confirm which Groups have Use vs Edit access
- Keep a staging copy of the app for testing major changes before deploying to the production app URL

## Frequently asked questions

### Do Retool users see my changes immediately when I edit an app, or only after I publish?

Users always see the most recently published release, not your in-progress edits. When you edit the app in the editor, you're modifying the draft. Only after you publish a release (via Manage Releases → Create Release) do users see the changes. This gives you a safe editing environment without affecting live users.

### How many release versions does Retool store?

Retool stores an unlimited history of published releases. All previous releases appear in the Release Manager and can be activated (rolled back to) at any time. Releases are never automatically purged. This means you always have a rollback option regardless of how old the last stable release was.

### Can I deploy a Retool app to a custom URL or embed it in another website?

Yes. Retool apps can be accessed at custom domains (requires DNS setup — see the custom domains tutorial). For embedding, Retool apps support iframe embedding — copy the app URL and embed it in an <iframe> tag. Note that users must be authenticated to Retool to access embedded apps unless you configure public access in app permissions.

---

Source: https://www.rapidevelopers.com/retool-tutorial/how-to-deploy-a-retool-app-to-production
© RapidDev — https://www.rapidevelopers.com/retool-tutorial/how-to-deploy-a-retool-app-to-production
