tutorial

How to Create an Internal Tool with Retool and PostgreSQL

A tutorial for building a CRUD admin panel using Retool connected to a PostgreSQL database. Covers data source connection, table components, detail views, create/update/delete operations, search, role-based access, and security. Built in 6 hours for a 20-person operations team at $200/month versus an estimated 3-4 weeks for custom development.

Overview

Internal tools (admin panels, dashboards, CRUD interfaces) consume a disproportionate amount of engineering time relative to their complexity. Retool is a low-code platform for building internal applications by connecting to databases and APIs, dragging pre-built UI components, and writing queries. This tutorial covers building a CRUD admin panel connected to a PostgreSQL database.

When to Use Retool

Retool is best suited for internal tools that:

  • Need to be built in hours or days, not weeks
  • Require direct database access (read and write)
  • Serve internal teams (operations, support, finance) rather than external customers
  • Need forms, tables, charts, and action buttons

As of April 2026, Retool offers a free tier for up to 5 users with unlimited apps. The Team plan costs $10/user/month. Self-hosted options are available for Enterprise customers.

Prerequisites

  • Retool account (free tier or Team plan)
  • PostgreSQL database accessible from the internet (or Retool self-hosted for private networks)
  • Database credentials with appropriate read/write permissions

Step 1: Connect the PostgreSQL Data Source

  1. In Retool, navigate to Resources > Create New > PostgreSQL
  2. Enter connection details:
    • Host: The database hostname or IP address
    • Port: 5432 (default)
    • Database name: The target database
    • Username: A dedicated Retool service user
    • Password: The service user password
  3. Enable SSL if the database requires encrypted connections
  4. Click "Test Connection" to verify, then "Save"

For production databases, create a read-write user with access limited to the specific tables the internal tool needs. Avoid using superuser credentials.

Step 2: Create a New Application

Click "Create New" > "App" and name it (for example, "Order Management Panel"). Retool opens the application editor with a blank canvas.

The editor has three main areas:

  • Canvas (center) — Drag and arrange UI components
  • Component panel (left) — Library of pre-built components
  • Query editor (bottom) — Write and manage database queries

Step 3: Write the Data Query

Click "+" in the query editor to create a new query. Select the PostgreSQL resource. Write a SELECT query:

SELECT
  id,
  customer_name,
  email,
  order_date,
  status,
  total_amount
FROM orders
ORDER BY order_date DESC
LIMIT 100

Name the query getOrders. Click "Run" to test. The results appear in the query output panel.

Step 4: Add a Table Component

Drag a "Table" component from the component panel onto the canvas. In the table's properties panel:

  • Set Data to {{ getOrders.data }}
  • Configure column visibility (hide internal IDs, format dates, add currency symbols)
  • Enable sorting and filtering
  • Enable row selection (single or multi-select)

The table automatically populates with the query results and updates when the query re-runs.

Step 5: Add a Detail View

Add a "Container" component to the right of the table. Inside it, add:

  • Text Input components for editable fields (customer_name, email, status)
  • Number Input for total_amount
  • Date Picker for order_date
  • Text components for read-only fields (id, created_at)

Bind each component to the selected table row:

  • Customer Name input: Default value = {{ table1.selectedRow.customer_name }}
  • Email input: Default value = {{ table1.selectedRow.email }}
  • Status input: Default value = {{ table1.selectedRow.status }}

When a user clicks a row in the table, the detail view populates with that row's data.

Step 6: Add Update and Delete Queries

Create an update query named updateOrder:

UPDATE orders
SET
  customer_name = {{ customerNameInput.value }},
  email = {{ emailInput.value }},
  status = {{ statusInput.value }},
  total_amount = {{ totalAmountInput.value }}
WHERE id = {{ table1.selectedRow.id }}

Create a delete query named deleteOrder:

DELETE FROM orders WHERE id = {{ table1.selectedRow.id }}

Both queries use Retool's {{ }} template syntax to reference component values.

Step 7: Add Action Buttons

Add "Button" components to the detail view:

  • Save button: On click, run updateOrder query, then run getOrders to refresh the table
  • Delete button: On click, show a confirmation dialog, then run deleteOrder and getOrders

Configure the Save button's event handler:

  1. Click the button component
  2. Add event handler: "Click" > "Run query" > updateOrder
  3. Add a second handler: On success of updateOrder > "Run query" > getOrders
  4. Add a third handler: On success > "Show notification" > "Order updated"

Step 8: Add a Create Form

Add a "Modal" component triggered by a "New Order" button. Inside the modal, add input components for each required field. Create an insert query named createOrder:

INSERT INTO orders (customer_name, email, order_date, status, total_amount)
VALUES (
  {{ newCustomerName.value }},
  {{ newEmail.value }},
  {{ newOrderDate.value }},
  {{ newStatus.value }},
  {{ newTotalAmount.value }}
)

Add a "Submit" button inside the modal that runs createOrder, closes the modal, and refreshes getOrders.

Step 9: Add Search and Filtering

Add a "Text Input" component above the table for search. Modify the getOrders query:

SELECT id, customer_name, email, order_date, status, total_amount
FROM orders
WHERE
  ({{ !searchInput.value }} OR customer_name ILIKE {{ '%' + searchInput.value + '%' }}
   OR email ILIKE {{ '%' + searchInput.value + '%' }})
ORDER BY order_date DESC
LIMIT 100

Set the search input to trigger getOrders on change (with a debounce of 300ms to avoid excessive queries).

Step 10: Deploy and Share

Click "Share" in the top-right corner. Retool apps are accessible via URL within the Retool workspace. Set permissions:

  • Admin: Full access to edit the app and run all queries
  • User: Can use the app but not edit it
  • Viewer: Read-only access

Security Considerations

  • Use parameterized queries (Retool's {{ }} syntax automatically parameterizes values to prevent SQL injection)
  • Create a database user with minimum required permissions
  • Enable Retool audit logs to track who made changes
  • Use Retool environments (staging/production) to prevent accidental changes to production data

Editor's Note: We built an order management panel in Retool for a 20-person operations team at an ecommerce company. Total build time: 6 hours from blank canvas to deployed app with CRUD operations, search, and role-based access. The same tool would have taken an estimated 3-4 weeks to build as a custom React application. Retool cost: $10/user/month for 20 users = $200/month. The main limitation: Retool apps are functional but not visually polished. They serve internal teams well, but the UI is not suitable for customer-facing tools. Additionally, complex business logic (multi-step validation, conditional workflows) requires JavaScript queries within Retool, which reduces the low-code advantage.

Last updated: | By Rafal Fila

Tools Mentioned

Related Guides

Related Rankings

Common Questions