Skip to content
Select themeSelect language

Import a Windmill repository

SupaCloud can import a Windmill wmill sync repository — its flows, raw apps, and scripts — into a workspace as native workflows. When the repository ships database migrations under db/migrations/, SupaCloud applies that schema onto a PostgreSQL resource you choose during the import, so the imported flows have their tables on first run.

This is an admin task: the import endpoint requires a workspace admin.

The Windmill repository import wizard — its step indicator above the repository URL and credential fields.The Windmill repository import wizard — its step indicator above the repository URL and credential fields.
  • You are a workspace admin.
  • The repository is reachable: a git URL plus, for a private repository, a git credential configured under Resources.
  • If the repository contains a db/migrations/ folder, create (or identify) a PostgreSQL resource under Resources to host the shared schema. For production, prefer a least-privileged role scoped to that schema rather than a superuser.
  1. Open the import wizard. Go to Workflows and choose Import → Windmill repository.

  2. Point at the repository. Enter the git URL and, for a private repository, select the git credential. SupaCloud clones the repository and scans it into an import plan — the flows, apps, and scripts it found, and any db/migrations/ it will apply.

  3. Bind the database resource. If the plan includes a database schema, pick the PostgreSQL resource to apply it onto. This binding is the one deployment-specific choice; SupaCloud reads the schema name and isolation from the repository.

  4. Review and apply. Confirm the plan. SupaCloud creates the workflows (each keeps its Windmill folder in the name, so f/blockworx/bank_sync imports as blockworx/bank_sync), records any schedules and HTTP triggers, and applies the database schema onto the resource you bound.

A repository whose db/migrations/ folder carries no SupaCloud db/namespace.yaml is still imported with no manual setup: SupaCloud infers the schema name from the CREATE SCHEMA statement and the tenant isolation from the SQL. A schema whose tables declare an entity column is isolated per entity; otherwise it is shared with no per-tenant overlay.

The schema is applied find-or-create by name, append-only and checksum-guarded — re-running the import never re-applies a migration that already ran. To override the inferred shape, add a db/namespace.yaml to the repository; it takes precedence.

A Windmill flow module often reads a credential or a setting through a resource("f/…") or a variable("u/…") reference. SupaCloud imports these as real bindings on the generated code node — not as dead placeholders.

  • resource("f/…") becomes a resource binding. A code node that binds a resource runs on the credentialed sandbox (Python/TypeScript) with deny-by-default egress: the script can reach only the bound resource’s host, and reads the resolved credential through a host-mediated accessor — it never holds the raw secret. A postgresql resource additionally grants a host-mediated guarded database call (read-only by default; see below). The converter maps each reference to a workspace resource by name and emits a warning for any binding you should verify or re-bind — open the node in the builder and confirm the resource it points at exists in this workspace.

    The name is folder-qualified: the Windmill folder and the resource name are joined with an underscore, so f/blockworx/imap_info becomes blockworx_imap_info and f/c2ost/imap_info becomes c2ost_imap_info. Two folders that use the same resource name therefore stay two separate resources — they never collapse onto one shared credential. The f/ or u/ prefix is dropped; every other path segment is kept, lowercased, with anything other than a letter or digit turned into an underscore. f/shared/anthropic becomes shared_anthropic — the shared folder is qualified like any other.

  • variable("u/…") becomes a workspace env-var injection. The matching workspace environment variable (by key — the last path segment) is resolved host-side at run time and injected into the node, least-authority: only the variables the script actually reads are injected. A secret-typed variable is decrypted host-side and never stored in the workflow definition. Ensure an env var of that key exists under Resources → Environment variables.

A code node that binds no resource stays hermetic (no network, no database) — unchanged from a plain imported snippet. Bindings are a first-party, workspace-owned capability; marketplace-published workflows never carry them.

Windmill calls a step’s main(...) function for you. SupaCloud runs the step’s file, so the import adds the call itself — you do not rewrite the entrypoint by hand:

  • the arguments come from the flow’s input_transforms, matched by parameter name (never by position, so a re-ordered input cannot swap two arguments);
  • an async entrypoint is awaited (TypeScript) or driven to completion (Python), so the step returns a value rather than a pending promise;
  • the return value becomes the step result the next step reads. A step that returns nothing produces no result — that is a valid outcome, not an error;
  • an entrypoint that throws now fails the step with the error and its stack in the log, instead of finishing successfully with nothing to show;
  • a result larger than the step-result limit fails with a message naming the limit and the actual size. Nothing is silently cut short.