Guides
Retool Dynamic Column Settings: Set Labels, Order & More
If you've ever tried to rename a database column like cost_per_event into something human-readable like "Cost per Event" inside a Retool table, you've probably hit a wall. The default approach forces you to rewrite your transformation query just to change a header — and if that transformation has downstream dependencies, it turns a one-line UI tweak into a full refactor. The good news: Retool's dynamic column settings are designed to solve exactly this problem, letting you control column labels, order, width, and editability entirely through a JSON config object. Here's how to use it properly.
What Are Retool Dynamic Column Settings?
Dynamic column settings is a table component property that accepts a JavaScript array of column configuration objects. Instead of manually clicking each column header in the Retool UI to rename or reorder it, you pass a structured array and Retool applies those settings at render time. This is a huge win for maintainability — your column presentation logic lives in one place, separate from your data-fetching logic.
The feature is especially valuable when you're building tables with variable or unknown columns (for example, columns named 0, 1, 2 from a positional SQL result), or when you're using the table inside a module where you can't directly click into column settings from a parent app.
How to Set Column Labels Dynamically in Retool
To map a raw column name to a human-friendly display label, use the name and label properties inside your dynamic column settings array. Open your table component, find the Dynamic column settings field, and enter something like this:
[{ "name": "cost_per_event", "label": "Cost per Event", "type": "numeric" }, { "name": "other_metric", "label": "Something Entirely Different", "type": "integer" }]
The name field must match the exact key returned by your data source. The label field is what the user sees as the column header. The type field controls how Retool formats and renders the cell value.
How to Control Column Order Dynamically
Column order in Retool tables defaults to the key order of the objects in your dataset — which is often unpredictable, especially with API responses or complex SQL joins. You can enforce a specific display order by adding an order property to each column config object:
[{ "name": "cost_per_event", "label": "Cost per Event", "type": "numeric", "order": 0 }, { "name": "other_metric", "label": "Something Entirely Different", "type": "integer", "order": 1 }]
Lower numbers appear first. This is particularly useful for internationalised apps where column order may differ by locale, or when building module-based tables where the parent app can't directly manipulate column positions.
How to Make Columns Editable via Dynamic Settings
One of the most-requested additions to dynamic column settings is the ability to set editable programmatically. Rather than clicking through each column's settings panel in the UI, you can declare editability inline:
[{ "name": "cost_per_event", "label": "Cost per Event", "type": "numeric", "order": 0, "editable": true, "width": 150 }, { "name": "other_metric", "label": "Something Entirely Different", "type": "integer", "order": 1, "editable": false, "width": 200 }]
Setting editable: true enables inline editing on that column. The width property sets the column's pixel width. Both properties save you from repetitive manual configuration, especially when the column list itself is dynamic.
Why You Should Use Dynamic Column Settings Instead of Transformations
The common workaround for renaming columns is to run a JavaScript transformation that remaps all the keys — something like converting cost_per_event to Cost per Event across every row. This works, but it creates serious maintenance headaches:
- Any component reading
table1.selectedRowortable1.sortedColumnnow gets the transformed key name back, not the original database key — forcing you to reverse-map it before writing back to your database. - Dependent queries or transformations that reference specific keys by name all break the moment you rename a key.
- You end up with a layer of "cosmetic" code mixed into data-fetching logic, making both harder to debug.
Dynamic column settings keep your data layer clean. Your query returns raw column names, your database write uses those same raw names, and the label mapping lives entirely in the table's presentation config. That separation is exactly how maintainable internal tools should be structured.
Step-by-Step: Setting Up Dynamic Column Labels in a Retool Table
- Step 1: Select your table component in the Retool canvas.
- Step 2: In the right-hand panel, locate the Dynamic column settings field (under the Columns section).
- Step 3: Click the field and switch to JS mode using the
{}toggle. - Step 4: Enter your column config array, using
nameto match your data keys andlabelfor the display header. - Step 5: Add
order,editable,width, andtypeproperties as needed. - Step 6: Reference a query or state variable to make the config fully dynamic — for example,
{{ columnConfigQuery.data }}if your column definitions come from a database or API.
Current Limitations and What's on Retool's Roadmap
As of the time of writing, support for label and editable via dynamic column settings has been filed as an internal feature request by the Retool team. The Retool community has been vocal about these gaps — particularly for internationalised apps that need to display different column headers per language, and for module-based tables where UI-level column editing isn't accessible. If you need this capability right now, the most reliable workaround is to keep your transformation output keyed by the original database column names and use a dedicated column label map object as a Retool state variable, then reference it inside a custom column header if your Retool version supports it.
Watch the original community thread and Retool's changelog for updates — this is one of the most upvoted table feature requests in the community.
Ready to build?
We scope, design, and ship your Retool app — fast.