# How to migrate a Pipedream GitHub Sync repository to n8n

> Source: https://workflowexit.com/pipedream-github-sync-to-n8n · Updated 2026-10-13

If a Pipedream project used GitHub Sync, its repository already holds most of an export. Each workflow has a `workflow.yaml` (schema `workflow/2022.04`) with its steps in order, action keys and versions, configured values and `{{ }}` expressions, and each code step has its source in an `entry.js`, `entry.mjs` or `entry.py` file. What the repository lacks is trigger settings (it keeps only trigger IDs), secret values (they're encrypted), environment variable values, data store records and the code of private components. Download the `production` branch, drop it on the [free report](/report), and copy the trigger settings from the Pipedream UI before workflows stop on **March 31, 2027**.

## What a synced repository looks like

One Pipedream project syncs to one repository. Pipedream hasn't published a definition of the YAML, and its FAQ says one isn't available yet. What follows comes from Pipedream's own example and from 172 workflows we analyzed in 47 public synced repositories.

```text
orders-project/                     branch: production
├── README.md
├── new-order-to-slack-p_AbC123/
│   ├── workflow.yaml
│   ├── .workflow.state
│   ├── normalize_order/
│   │   └── entry.js
│   └── score_lead/
│       └── entry.py
└── Reports/
    └── weekly-summary-p_DeF456/
        ├── workflow.yaml
        └── .workflow.state
```

- **Workflow folders** are named `<slug>-p_<id>`, where `p_...` is the workflow ID. Project folders are ordinary directories and can nest.
- **`.workflow.state`** holds `schema: workflow.state/2022.04` and the workflow ID.
- **Each code step** has a folder named after the step. JavaScript steps can have their own modules next to them, imported with `./` paths.
- **The `production` branch** is the deployed state. Pipedream deploys whatever is merged into it. Changes in Pipedream are made in development branches, and undeployed edits from workflows moved into a project land in branches that start with `undeployed-changes`.

## Inside workflow.yaml

This example uses the same format:

```yaml
schema: workflow/2022.04
name: New order to Slack
triggers:
- id: hi_Gh7Kq2P
steps:
- namespace: normalize_order
  runtime: nodejs20.x
  uses: "./normalize_order/entry.js"
  props:
    order: "{{steps.trigger.event.body}}"
- namespace: post_message
  runtime: nodejs20.x
  uses: slack_v2-send-message@1.0.2
  props:
    slack:
      authProvisionId: apn_Xy12Ab3
    conversation:
      __lv:
        label: "#orders"
        value: C01ABCDE2FG
    text: "New order {{steps.normalize_order.$return_value.id}}"
```

The top-level keys:

| Key | What it holds |
|---|---|
| `schema` | Always `workflow/2022.04` |
| `name` | The workflow's name |
| `inactive` | `true` when the workflow is turned off. A missing key means it's on. |
| `settings` | Run settings such as `error_notification`, `lambda_timeout` (seconds), `lambda_memory` (MB), `auto_retry` and `concurrency` |
| `triggers` | Trigger IDs only. The prefix gives the type: `hi_` HTTP, `ti_` schedule, `dc_` app event source, `ei_` email, `sub_` events from another workflow or source. |
| `steps` | Steps in order: `namespace` (the step name), `runtime`, `uses`, `props`, and optionally `disabled` and `notes` |

Workflow Exit doesn't carry `settings` over. In n8n, set a timeout in the workflow's settings, turn on Retry On Fail for the nodes that should retry, and replace error notifications with an error workflow, a separate workflow that starts with an Error Trigger node.

`uses` takes three forms:

- `./<step>/entry.js`, `entry.mjs` or `entry.py`: a code step whose source is in the repository.
- `<app>-<action>@<version>`, such as `slack_v2-send-message@1.0.2`: a registry action pinned to a version.
- `@<workspace>/<key>@<version>`: a private component. Its code isn't in the repository.

Prop values come in a few encodings:

| Encoding | Meaning |
|---|---|
| `"{{steps.x.$return_value}}"` | An expression. It can be any JavaScript, not only a path. |
| `authProvisionId: apn_...` | A connected account, without its token |
| `__lv: {label, value}` | A choice from a dropdown. The converter uses `value`. |
| `storeId: ds_...` | A data store, without its records |
| `_enc: ...` | A secret, encrypted. It can't be decrypted outside Pipedream. |
| `__configurableProps: [...]` | Prop declarations of a Python step |
| `_filter: {continue, rules}` | The settings of a built-in Filter step |

## What the repository doesn't contain

| Missing | What the YAML has instead | What to do |
|---|---|---|
| Trigger settings | A trigger ID | Copy URLs, auth, schedules and source options from the Pipedream UI |
| Secret values | `_enc` ciphertext | Re-enter them in n8n credentials or Variables |
| Connected accounts | `authProvisionId` | Create n8n credentials |
| Environment variables | References such as `process.env.NAME` or `os.environ` | Copy the values from the original service |
| Data store records | `storeId` | Export them, as in [saving data stores](/pipedream-data-stores) |
| Private components | `@workspace/key@version` | Keep your own copy of the source |
| Event history | Nothing | Save a few sample events for testing |

Branch blocks are an open question. None of the 172 public workflows we looked at had an if/else, switch or parallel block, so we can't say how GitHub Sync stores their branches. If you use them, check the converted branches with extra care, or pull those workflows through the REST API as described in [exporting on Free or Basic](/export-pipedream-workflows-free-plan).

## Write down trigger settings now

Because the YAML only names each trigger, record the settings from the Pipedream UI while you can still open it:

- **HTTP (`hi_`):** the endpoint URL, which you need for the list of senders to update, plus the authorization setting and how the endpoint responds.
- **Schedule (`ti_`):** the cron expression or interval, and the time zone.
- **App event source (`dc_`):** which app and trigger it is, and its options, such as a channel, a table or a polling interval.
- **Email (`ei_`):** the address, so you can forward that mail to a mailbox n8n reads.
- **Subscription (`sub_`):** which workflow or source emits the events.

## Upload the repository to the free report

1. **Get the `production` branch.** Download it from GitHub as a ZIP, or use a local clone. If some work exists only in a development branch, merge it in Pipedream first, or download that branch instead.
2. **Open the [report page](/report)** and drop the ZIP, or click **Choose a folder** and pick the repository folder. The report skips `.git` and `node_modules`, and it ignores GitHub Actions files under `.github/`.
3. **Read the warnings.** The report infers each trigger's type from its ID prefix and says so. Where a schedule or endpoint setting is missing, it tells you to copy it from Pipedream.
4. **Prefer the command line?** Run `node workflow-exit.mjs report ./orders-project` with the [CLI](/cli/workflow-exit.mjs) to write `REPORT.md` locally.

The report runs in your browser, so the repository isn't uploaded to build it. An upload can hold up to 20,000 files and 300 MB unpacked.

## How the repository converts

- **Code steps.** `entry.js` and `entry.mjs` files become n8n Code nodes with the compatibility layer, and sibling modules they import with `./` paths are bundled into the node. `entry.py` steps need a rewrite, covered in [Python steps in n8n](/pipedream-python-steps-to-n8n).
- **Actions.** Registry actions with a known mapping become native n8n nodes; see the [app-by-app notes](/apps). The rest get a placeholder node that lists your original props, or an HTTP Request node from the optional AI rewrite.
- **Expressions.** `{{steps.normalize_order.$return_value.id}}` becomes an n8n expression that reads the node with the same name.
- **Secrets and accounts.** `_enc` values are treated like redacted secrets, and each `authProvisionId` becomes a credential to create. `CHECKLIST.md` lists both.
- **Triggers.** `hi_` becomes a Webhook that accepts every method, with a Respond to Webhook node when a step calls `$.respond()`. `ti_` becomes a Schedule Trigger set to every hour, with a checklist item to enter the real schedule, as covered in the [schedule guide](/pipedream-schedule-to-n8n). `ei_` becomes an IMAP email trigger. `dc_` and `sub_` become placeholders with a note, because the YAML doesn't say what they were.
- **Structure.** Disabled steps stay disabled, and project folders are kept in the output.

## Checklist

1. Confirm that `production` matches what runs in Pipedream, and merge or download any branch that holds work you need.
2. Record the settings of every trigger: URLs, authorization, schedules, time zones and source options.
3. Collect the values behind every `_enc` prop and every environment variable the code reads.
4. Export the records of every data store referenced by a `storeId`.
5. Save a few sample events per workflow for testing.
6. Run the report, convert, import into n8n, and test each workflow before you move its senders or turn off its Pipedream copy.

The [free migration report](/report) reads your GitHub Sync repository as it is and shows, workflow by workflow, what converts automatically and what you need to fill in, starting with trigger settings. If you don't have a synced repository, [how to export Pipedream workflows](/export-pipedream-workflows) covers the other ways to get your workflows out.

## Frequently asked questions

### Is a GitHub Sync repository enough to migrate to n8n?

Mostly. It has each workflow's steps, code, action versions and configured values. It lacks trigger settings, secret values, environment variables, data store records and the code of private components, which you collect separately.

### Which branch should I use?

production. Pipedream deploys whatever is merged into production, so it matches what runs. Development branches, including ones that start with undeployed-changes, can hold edits that were never deployed.

### Can I decrypt the _enc values in workflow.yaml?

No. GitHub Sync stores secret props encrypted, and only Pipedream can read them. Re-enter those values in n8n credentials or Variables.

### Can n8n import workflow.yaml directly?

No. n8n imports its own workflow JSON, made of nodes and connections. Each workflow.yaml has to be converted first, by hand or with a converter.

### Which Pipedream plans include GitHub Sync?

Pipedream's docs don't list them. The plan-limit data its dashboard loads names Advanced as the lowest plan with GitHub Sync, and syncing to GitHub Enterprise Cloud needed the Business plan.

### Will the repository disappear when Pipedream deletes Workflows data?

The repository lives in your GitHub account, not on Pipedream, so it isn't part of the Workflows data Pipedream deletes by April 30, 2027. Keep a local copy anyway.
