Reporting workflow progress back to the app (multiple responses?)

Hi all,

I’m working with Retool Workflows and wondering what the best approach is for reporting progress back to the app during a long-running workflow.

Ideally, I’d like to send intermediate updates (e.g. step 1 complete, step 2 running, etc.) back to the retool app so the UI can reflect progress in real time. From what I understand, workflows only return a single response at the end, so I’m not sure if there’s a built-in way to handle this.

Has anyone implemented something like this?

Example:

I want my app to show the progress of the workflow. e.g. in this case say 20% and then afte a few seconds 80% …. so O can show the user the progress

Thanks!

1 Like

Hi @Pedram,

You’re correct that Retool workflows currently return only a single final response, so there isn’t built-in support for streaming or intermediate updates. A practical workaround for this is to use a database polling pattern.

Here’s a simple approach:


Step 1 — Create a progress table

Set up a table to track workflow execution status:

CREATE TABLE workflow_progress (
  job_id TEXT,
  progress INT,       -- 0 to 100
  status TEXT,        -- 'running' | 'done' | 'error'
  message TEXT,
  updated_at TIMESTAMP DEFAULT now()
);

Step 2 — Update progress within the workflow

At key stages in your workflow, update the progress and message. For example:

UPDATE workflow_progress 
SET progress = 20, message = 'Step 1 complete' 
WHERE job_id = '{{startTrigger.data.job_id}}';

Continue updating as the workflow progresses (e.g., 80% after step 2, and finally 100% with status = 'done' once completed).


Step 3 — Poll from your Retool app

Create a query in your Retool app:

SELECT * 
FROM workflow_progress 
WHERE job_id = {{ jobIdState.value }};

Enable “Run on a timer” (e.g., every 2 seconds).

Bind a Progress Bar component to:

{{ pollProgress.data.progress[0] }}

To stop polling once the workflow completes, use a JS query:

if (pollProgress.data.status[0] === 'done') {
  pollProgress.setTriggerOnLoad(false);
}

This approach provides a near real-time progress update experience for users.

For additional context, you can refer to this forum thread: