Originally published on flowrunner.ai. I run FlowRunner, so this is our product. The workflows are Raymond Camden's, used with his permission.

Every demo on this page starts from a real Pipedream workflow and ends as a working, tested FlowRunner flow. We show the files that went in, what the builder made from them, what still needed a person, like reconnecting accounts or picking the right spreadsheet, and where the result differs from the original.

Pipedream workflows come out in one of two formats, and the builder reads both. If your project used GitHub Sync, your repo already holds each workflow as a workflow.yaml file with one code file per step. Otherwise, Pipedream's Export Workflows tool gives you a ZIP with one JSON file per workflow. Each demo says which format it started from. For the shutdown dates, what the export leaves out, and where each Pipedream piece lands in FlowRunner, see our Pipedream migration guide.

We add conversions as we do them. If you'd like yours converted, send us your files and we'll do it for free. With your permission, it goes on this page with anything identifying removed.

How the conversion works

FlowRunner's Prompt to Flow works through an MCP server. Add it to Claude, ChatGPT, Claude Code, Codex, or Cursor, sign in to your FlowRunner account, paste in a workflow's files, and ask for the same thing as a FlowRunner flow. In Claude Code that's one command:

claude mcp add --transport http flowrunner https://app.flowrunner.ai/mcp 

The builder reads the triggers, steps, code, and branches in the file and builds the flow in your workspace. It rewrites Python steps in JavaScript, and it asks about anything the file can't tell it.

What it can't do is bring your credentials across. Neither format carries connected accounts or secrets, and neither carries your data stores, so every conversion ends with a short list of things to finish by hand. Each demo below shows that list as the builder gave it.

A moderated guestbook, in three workflows

Raymond Camden ran the guestbook on his site with three Pipedream workflows, and he keeps them public in his General-Pipedream-Stuff repo. Thanks to Raymond for letting us use them. Together they make a small moderation loop: a visitor's entry lands in a Google Sheet, Raymond gets an email with an approve link, and the site only shows entries he approved.

The input for all three was his GitHub Sync files, exactly as they sit in the repo: each workflow's workflow.yaml plus one JavaScript file per code step. Each conversion started with the same request, followed by the files:

Rebuild this Pipedream workflow as a FlowRunner flow. It comes from Pipedream's GitHub Sync: workflow.yaml lists the trigger and the steps in order, and the source of each code step follows it. Keep the same behavior. Before you build, tell me anything you can't map one to one, and ask me about anything the files don't say (for example the trigger's schedule or URL, which GitHub Sync doesn't record).

Because the request asks for it, the builder listed what it couldn't map one to one and asked its questions before building anything. All three flows were then connected to a test spreadsheet and a Gmail account and tested end to end.

1. Add Guestbook Entry

A visitor's form posts a name and a comment. The workflow checks both are there, adds a row to the sheet with Approved set to FALSE, and emails Raymond the entry with a "Click to Approve" link. (Original files)

schema: workflow/2022.04 name: Add Guestbook Entry settings: error_notification: true triggers: - id: hi_mJH1wmn steps: - namespace: validate runtime: nodejs20.x uses: "./validate/entry.js" - namespace: add_single_row runtime: nodejs20.x uses: google_sheets-add-single-row@2.1.2 props: googleSheets: authProvisionId: apn_DphexA sheetId: __lv: label: Guestbook value: 1RLspI8iuC-Ng8Fco8zV-ynpxdPLm7MgoXm5jnlo0Tpk sheetName: __lv: label: Sheet1 value: Sheet1 hasHeaders: 'Yes' col_0000: "{{steps.trigger.event.body.name.replace(/<.*?>/g,'')}}" col_0001: "{{steps.trigger.event.body.comment.replace(/<.*?>/g,'')}}" col_0002: "{{Date.now()}}" col_0003: 'FALSE' - namespace: create_email_body runtime: nodejs20.x uses: "./create_email_body/entry.js" - namespace: send_email_to_self runtime: nodejs20.x uses: email-send-email-to-self@0.4.4 props: subject: New Guestbook Entry text: "{{steps.create_email_body.$return_value}}" html: "{{steps.create_email_body.$return_value}}" 

The Add Guestbook Entry flow on the FlowRunner canvas: Start, an HTTP trigger, a Validate: name and comment present? condition whose Yes branch leads to Prepare row, Add single row (Google Sheets), Create email body, and Send email to self (Gmail).

Pipedream FlowRunner
HTTP trigger External Callback. The posted JSON body becomes the trigger data.
validate code step, which ends the run with $.flow.exit A Condition: name and comment both present. The No branch has nothing after it, so the run ends there.
Code inside the column fields (strip HTML tags, Date.now()) A small Custom Cloud Code step that prepares the row. FlowRunner fields take references to earlier results, not code.
Google Sheets, Add Single Row Google Sheets, Add Row. It returns the range the row landed in, which the approve link needs.
create_email_body code step Custom Cloud Code, with Raymond's HTML almost unchanged.
The APPROVE_GB environment variable The Approve flow's address, written into the email code step.
Email, Send Email To Self Gmail, Send Email, addressed to the owner.

The two code steps carry Raymond's logic over. The first holds what Pipedream ran inside the column fields: stripping HTML tags from the name and comment, and the Date.now() timestamp.

The Prepare row code step in the Code Editor: name and comment arguments bound to the incoming request, and four lines that strip HTML tags from both and return the row in sheet order, Name, Comment, Date.now(), FALSE.

The second is Raymond's email HTML, with the approve flow's address passed in where his code read the APPROVE_GB variable, and the row's range taken from the Add Row step.

The Create email body code step: arguments for name, comment, updatedRange from the Add Row step, and approveUrl, and Raymond's HTML template building a Click to Approve link from the approve URL and the encoded range.

Left to finish by hand: connect Google Sheets and Gmail, pick the spreadsheet, set the address the email goes to, and start the flow.

Tested: a test entry added the row, with Approved set to FALSE, and the email arrived with a working approve link.

The Guestbook spreadsheet after the test entry: headers Name, Comment, Date, Approved, and one row reading Ada, Hello from the test, 1791494504814, FALSE.

Notes: the builder replaced the validation code with a Condition block, which shows on the canvas instead of hiding in code. Pipedream's Send Email To Self needed no setup; on FlowRunner the email goes through your own email account, so you connect one.

2. Approve Guestbook Entry

The approve link in the email opens this workflow with the new row's range in the address. It sets that row's Approved cell to TRUE, and the entry shows up on the site. (Original files)

The Approve Guestbook Entry flow on the FlowRunner canvas: Start, an HTTP trigger, a Find Approved cell code step, and Update cell (Google Sheets).

Pipedream FlowRunner
HTTP trigger External Callback. The range in the link becomes the trigger data.
The cell expression range.split(':').pop() in the Update Cell step A one-line Custom Cloud Code step that picks the Approved cell, for example D5.
Google Sheets, Update Cell Google Sheets, Update Cell by A1, set to TRUE.
A code step that redirects the browser to the guestbook page Not reproduced. See the notes.

Raymond's one-line cell expression became a one-line code step, and its result feeds the Google Sheets block's cell address.

The Find Approved cell code step: one argument, range, bound to the approve request, and a single line returning the part of the range after the colon, with a comment showing 'Sheet1'!A5:D5 becoming D5.

The Update cell block configured as Google Sheets Update Cell by A1: Document Guestbook, Sheet 0, A1 Cell Address bound to the Approved Cell result, and Cell Value TRUE.

Left to finish by hand: connect Google Sheets and pick the spreadsheet, then start the flow.

Tested: clicking the approve link in the test email set that row's Approved cell to TRUE.

Notes: Raymond's last step sends the browser back to his guestbook page with a redirect. Our version doesn't, so the browser shows FlowRunner's run ID instead of the guestbook page.

3. Get Guestbook Entries

The guestbook page calls this workflow to get the approved entries. It reads the sheet, keeps the approved rows, and answers with them as JSON. (Original files)

The Get Guestbook Entries flow on the FlowRunner canvas: Start leads straight to Get values in range (Google Sheets), then Filter and map, then Return approved, with no trigger block, because the flow is called directly.

Pipedream FlowRunner
HTTP trigger plus a $.respond step that answers the caller A flow with no trigger block that ends in Return Result, called through the blocking Call Flow API, so the caller gets the answer in the same request.
Google Sheets, Get Values in Range (A2:D10000) Google Sheets, Get Rows. Rows come back keyed by the header names instead of by position, with no row cap.
filter_and_map code step Custom Cloud Code that reads the columns by name and returns name, comment, and date for each approved row.
return_approved code step ($.respond with JSON) Return Result, content type JSON.

Because the rows now come back keyed by their headers, the filter reads r.Approved and r.Name where Raymond's code read a[3] and a[0].

The Filter and map code step: a rows argument bound to the Guestbook Rows result, keeping rows whose Approved value is TRUE and returning name, comment, and date for each.

The Return approved block: Return Result with Content Type JSON and Result set to the Approved Entries list from the previous step.

Left to finish by hand: connect Google Sheets and pick the spreadsheet, then start the flow.

Tested: the call returned exactly what Raymond's workflow returns, the approved entries as a JSON array:

[{"name":"Ada","comment":"Hello from the test","date":"1791494504814"}] 

Notes: this is the one workflow whose trigger changed shape. A Pipedream HTTP trigger can answer its caller directly; on FlowRunner, a flow that answers its caller is called through the blocking API instead. The calling address includes your workspace key, so call it from a server and pass the key in a header rather than from the visitor's browser.