# How to Manage App Dependencies in Retool

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

## TL;DR

Retool app dependencies include: JS libraries loaded via Settings → Preloaded JS (org-wide) or App Settings → Scripts (per-app); query dependencies controlled by 'Depends on' settings in the Inspector; npm packages for Custom Component Libraries via package.json; and Module dependencies when one app uses another as a module. Load only what you need — unused libraries slow down app load times.

## Types of Dependencies in a Retool App

When people ask about 'dependencies' in Retool, they typically mean one of four things:

1. JavaScript library dependencies: external libraries (lodash, moment.js, chart.js, d3) loaded into the Retool JS execution environment via Preloaded JS.

2. Query dependencies: the execution order of queries. A 'fetch user' query must run before a 'fetch orders for user' query — this is managed via the 'Depends on' setting in a query's Inspector.

3. Custom Component Library (CCL) npm dependencies: if you've built a React-based custom component, it has a package.json with npm dependencies managed like any Node.js project.

4. Module dependencies: if your app uses Retool Modules (reusable sub-apps), those modules are dependencies of the parent app.

This tutorial walks through each type with practical management guidance.

## Before you start

- Editor or Admin access to a Retool app
- Understanding of what your app currently uses (external libraries, queries, custom components)
- For Custom Component Libraries: Node.js installed locally (the CCL CLI requires it)
- Basic familiarity with JavaScript library concepts

## Step-by-step guide

### 1. Add JavaScript library dependencies via Preloaded JS

External JavaScript libraries are the most common type of dependency in Retool apps. Add them in Settings → Preloaded JS/CSS (for org-wide availability) or App Settings → Scripts (for per-app scripts).

For CDN-hosted libraries, add the script URL in the Preloaded JS text area. For org-wide use (most common), use Settings → Preloaded JS. After adding, the library is available in all JS queries and transformers as a global variable.

```
// Settings → Preloaded JS: Load external libraries

// Option 1: Load via CDN URL (paste the URL into Preloaded JS, not the script tag)
// https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js
// https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js
// https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.0/chart.umd.min.js

// Option 2: Paste the library code directly into Preloaded JS (for offline/self-hosted)
// (Paste minified library source directly)

// After loading lodash, use it in JS queries:
const grouped = _.groupBy(query1.data, 'category');
const sorted = _.orderBy(query1.data, ['date', 'name'], ['desc', 'asc']);
const unique = _.uniqBy(query1.data, 'email');

// After loading moment:
const formatted = moment(dateValue).format('MMM DD, YYYY');
const daysAgo = moment(createdAt).fromNow();
```

**Expected result:** External library functions (_, moment, Chart, etc.) are available in all JS queries after loading via Preloaded JS.

### 2. Understand and manage query dependencies

Query dependencies define which queries must complete before another query runs. By default, queries in Retool can run independently (no dependency). But some queries depend on data from other queries — for example, a 'fetchOrderItems' query that needs `{{ fetchOrders.data[0].id }}`.

Retool handles this automatically if you reference `{{ anotherQuery.data }}` in a query — the query waits for the referenced query to complete. You can also set explicit 'Depends on' in a query's Inspector → Advanced → Depends on field.

View the query dependency graph: in the Code panel (left sidebar), look for the Dependencies or Graph view that shows the execution DAG.

```
// Query dependency example:

// Query 1: fetchUser (no dependencies)
SELECT * FROM users WHERE id = {{ current_user.id }}

// Query 2: fetchUserOrders (depends on fetchUser completing first)
// Retool auto-detects the dependency because of the {{ }} reference:
SELECT * FROM orders 
WHERE user_id = {{ fetchUser.data[0].id }}
ORDER BY created_at DESC

// Query 3: fetchOrderItems (depends on fetchUserOrders)
// Manually set 'Depends on: fetchUserOrders' in Inspector → Advanced
-- This query runs only after fetchUserOrders completes
SELECT oi.* 
FROM order_items oi
WHERE oi.order_id IN (
  SELECT id FROM orders WHERE user_id = {{ fetchUser.data[0].id }}
)
```

**Expected result:** Queries execute in the correct order: parent queries complete before dependent queries start.

### 3. Use the query 'Runs when' setting for conditional dependencies

Beyond dependency ordering, queries can be configured to only run when certain conditions are met. This is different from 'Depends on' — 'Depends on' controls ordering, while 'Runs when' controls whether a query runs at all.

In a query's Inspector → Interaction, find the 'Run query on page load' checkbox and the 'Only run when' condition field. Set conditions like 'Only run when selectedUserId.value is not null' to avoid running queries that would fail with undefined parameters.

```
// Query Inspector → Only run when condition:
// (These are typed in the Inspector field, not in the query itself)

// Only run this query when a row is selected in the table:
{{ table1.selectedRow !== null && table1.selectedRow.id }}

// Only run when a search term is long enough:
{{ searchInput1.value.length >= 3 }}

// Only run in production environment:
{{ retoolContext.environment === 'production' }}

// Only run when user is in the Admin group:
{{ current_user.groups.includes('Admin') }}
```

**Expected result:** Queries with 'Only run when' conditions don't fire on page load when conditions aren't met, preventing unnecessary database calls.

### 4. Manage npm dependencies for Custom Component Libraries

If you've built a Custom Component Library (CCL) using the Retool CLI, it has its own npm dependency management. The CCL is a standard React project with a package.json.

To add a dependency to your CCL:
1. Navigate to your CCL project directory
2. Run `npm install packageName --save`
3. Import and use it in your component code
4. Build and publish the updated library: `npm run build && npm publish`

Retool apps using the CCL automatically use the updated library version after re-importing.

```
# Terminal commands for CCL dependency management:

# Initialize a new CCL project
npx @retool/retool-ccl@latest init my-company-components
cd my-company-components

# Install npm dependencies
npm install recharts --save       # charting library
npm install date-fns --save       # date utility
npm install react-virtualized --save  # performance library for large lists

# Update a dependency
npm update recharts

# Check for outdated dependencies
npm outdated

# Build and publish to Retool
npm run build
npm publish

# Or publish to Retool directly (without npm registry):
npx retool-ccl deploy
```

**Expected result:** The CCL builds with the new dependency and the updated component is available in Retool apps.

### 5. Manage Module dependencies

Retool Modules are reusable sub-apps (mini apps) that can be embedded inside other apps. An app that uses a Module has a dependency on that Module. Module dependencies are managed by:

1. Adding the Module via the component panel (search 'Module')
2. Selecting the Module to use from your org's module list
3. Configuring module inputs: `{{ table1.selectedRow }}` passed as input to the module
4. Reading module outputs: `{{ moduleComponent1.outputVariable }}`

When a Module changes, all apps using it automatically get the update — no per-app changes needed. This is the key benefit of modules for dependency management.

```
// Module component in parent app:

// Module inputs (Inspector → Inputs section):
// Input name: selectedUser
// Input value: {{ table1.selectedRow }}

// Input name: currentEnvironment  
// Input value: {{ retoolContext.environment }}

// Reading Module outputs in parent app:
// After the module calls moduleOutputs.setValue({}):
{{ moduleComponent1.outputVariable }}

// Triggering parent app queries from Module output:
// Parent app query that references module output:
SELECT * FROM orders 
WHERE user_id = {{ moduleComponent1.selectedUserId }}
```

**Expected result:** The module component receives input data from the parent app and exposes output data that parent app queries can reference.

### 6. Audit and clean up dependencies to improve load times

Over time, apps accumulate unused queries, libraries, and components that slow down load times. Audit your app's dependencies:

1. In the Code panel (left sidebar), review all queries — delete any that are never triggered or referenced by other queries
2. In Settings → Preloaded JS, check which libraries are actually used across apps — remove unused ones
3. Review Custom Component Libraries for components never used in any app
4. Check Modules — are all imported modules still necessary?

Retool's State Inspector shows all active queries and their data, helping identify queries that run but produce no used output.

```
// JS Query: auditUnusedQueries
// Lists queries with no components referencing their .data
// NOTE: This is conceptual — Retool doesn't have a built-in audit API
// Manually check the following in the editor:

// 1. For each query in Code panel:
//    - Is query.data referenced by any component?
//    - Does any event handler trigger this query?
//    - Is it triggered by another query's success handler?

// 2. Check app load time with browser DevTools:
//    - Open Network tab before page load
//    - Count API calls on load
//    - Queries that load on page load but whose data is never used = candidates for deletion

// 3. Check Preloaded JS library usage:
const librariesLoaded = [
  'lodash (via _)',
  'moment',
  'chartjs (via Chart)'
];

// Manually verify each is used in at least one active query or component
return {
  note: 'Manually audit each library - check JS queries for usage',
  librariesLoaded
};
```

**Expected result:** Unused queries are deleted, unused libraries are removed from Preloaded JS, and app load time improves.

## Complete code example

File: `Settings → Preloaded JS (dependency loader)`

```javascript
// Retool Preloaded JS — Dependency Loader
// Settings → Preloaded JS/CSS → JavaScript tab
// Add CDN URLs (one per line) for libraries:
//
// https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js
// https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js
//
// Then add initialization code below:

// Configure moment.js defaults for your organization:
if (typeof moment !== 'undefined') {
  moment.defaultFormat = 'YYYY-MM-DD';
}

// Configure lodash (already globally available as _ after CDN load)
// No configuration needed — _ is available in all JS queries

// Utility functions available globally across all apps:
window.formatCurrency = function(amount, currency = 'USD') {
  return new Intl.NumberFormat('en-US', {
    style: 'currency',
    currency: currency,
    minimumFractionDigits: 2
  }).format(amount);
};

window.formatDate = function(dateString, format = 'MMM D, YYYY') {
  if (!dateString) return '—';
  return moment(dateString).format(format);
};

window.truncateText = function(text, maxLength = 50) {
  if (!text) return '';
  return text.length > maxLength ? text.substring(0, maxLength) + '...' : text;
};

console.log('[Retool] Preloaded dependencies initialized');
```

## Common mistakes

- **Loading large libraries (like full D3 or Three.js) in global Preloaded JS when they're only used in one app** — undefined Fix: Add heavy libraries in App Settings → Scripts (per-app scripts) rather than global Preloaded JS. This limits the performance impact to only the app that needs the library.
- **Creating circular query dependencies where Query A depends on Query B which depends on Query A** — undefined Fix: Review the dependency graph and break the cycle. Usually this means one query should run independently and the other should reference the first via {{ }}. If both truly need each other, merge them into a single JS query that orchestrates the logic.
- **Deleting a Retool Module that other apps depend on, causing those apps to break silently** — undefined Fix: Before deleting any Module, check which apps use it. Search in Retool for apps using the module name or do a cross-app audit. Deprecate the module gradually: add a deprecation warning in the module description, notify app owners, give them time to remove the dependency before deleting.

## Best practices

- Load JavaScript libraries via CDN URL in Preloaded JS rather than pasting minified code — CDN loads are cached by browsers and don't increase Retool's payload size
- Load heavy libraries (D3, Chart.js, Three.js) only in the specific apps that need them, not in global Preloaded JS
- Use Retool's built-in lodash (available as _ without loading it) and moment.js before adding external library dependencies
- Review Preloaded JS libraries quarterly — teams accumulate libraries they no longer use, slowing down every app load
- For Custom Component Libraries, pin dependency versions (exact versions in package.json, not ^semver ranges) to prevent unexpected breaking changes from upstream package updates
- Document module dependencies in app descriptions: 'This app uses the User Profile Module — do not delete that module'
- Use the 'Only run when' query condition to prevent dependent queries from firing with undefined inputs, avoiding null reference errors

## Frequently asked questions

### Does Retool include lodash and moment.js by default without loading them?

Retool includes lodash (as the _ global) and moment.js in its JavaScript execution environment by default — you don't need to add them to Preloaded JS. They're available in all JS queries and transformers without any setup. However, for the latest versions or specific features, you can override with your own CDN load.

### How do I check what JavaScript libraries are currently loaded in my Retool organization?

Go to Settings → Preloaded JS/CSS and review the list of URLs/code in the JavaScript tab. These are the org-wide libraries. For per-app scripts, go to App Settings → Scripts for each app. Retool doesn't provide a consolidated dependency report — you need to check both locations manually.

### Can I use ES modules (import/export syntax) in Retool JS queries?

No. Retool JS queries run in a custom execution context that doesn't support ES module import/export syntax. Use the CDN-loaded global variable approach instead: load a library in Preloaded JS and access it as a global (e.g., _, moment, Chart). If you need modern module-based code, build it in a Custom Component Library (CCL) which uses a standard Node.js build environment.

---

Source: https://www.rapidevelopers.com/retool-tutorial/how-to-manage-app-dependencies-in-retool
© RapidDev — https://www.rapidevelopers.com/retool-tutorial/how-to-manage-app-dependencies-in-retool
