Created
March 25, 2026 11:46
-
-
Save rubenfiszel/199f236e9334f1ffcbf71c6cebf47f2b to your computer and use it in GitHub Desktop.
Windmill: relative imports and wmill.runScript examples (Python & TypeScript)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Windmill: Relative Imports & wmill.runScript Examples | |
| Two patterns for reusing scripts in Windmill — **relative imports** (inlined, same job) and **wmill.runScript** (separate child job). | |
| --- | |
| ## Python | |
| ### `f/common/send_email.py` — reusable unit | |
| ```python | |
| from typing import Optional | |
| def main(to: str, subject: str, body: str, html: Optional[bool] = False): | |
| """Send an email via SMTP resource.""" | |
| import wmill | |
| import smtplib | |
| from email.mime.text import MIMEText | |
| smtp = wmill.get_resource("u/admin/smtp_server") | |
| msg = MIMEText(body, "html" if html else "plain") | |
| msg["Subject"] = subject | |
| msg["From"] = smtp["from"] | |
| msg["To"] = to | |
| with smtplib.SMTP(smtp["host"], smtp["port"]) as server: | |
| server.starttls() | |
| server.login(smtp["user"], smtp["password"]) | |
| server.send_message(msg) | |
| return {"sent_to": to, "subject": subject} | |
| ``` | |
| ### `f/notifications/send_signup_welcome.py` — uses it via relative import | |
| ```python | |
| import wmill | |
| def main(user_email: str, user_name: str): | |
| """Send a welcome email after signup.""" | |
| # Option A: relative import (both scripts must be in the same workspace) | |
| from f.common.send_email import main as send_email | |
| send_email( | |
| to=user_email, | |
| subject=f"Welcome, {user_name}!", | |
| body=f"<h1>Hey {user_name}</h1><p>Thanks for signing up.</p>", | |
| html=True, | |
| ) | |
| # Option B: wmill.runScript — runs it as a separate job (async, logged) | |
| wmill.run_script("f/common/send_email", args={ | |
| "to": "admin@company.com", | |
| "subject": f"New signup: {user_name}", | |
| "body": f"{user_name} ({user_email}) just signed up.", | |
| }) | |
| return {"notified": user_email} | |
| ``` | |
| --- | |
| ## TypeScript | |
| ### `f/common/send_email.ts` — reusable unit | |
| ```typescript | |
| import * as wmill from "windmill-client"; | |
| export async function main(to: string, subject: string, body: string) { | |
| const smtp = await wmill.getResource("u/admin/smtp_server"); | |
| const res = await fetch(smtp.api_url, { | |
| method: "POST", | |
| headers: { Authorization: `Bearer ${smtp.api_key}`, "Content-Type": "application/json" }, | |
| body: JSON.stringify({ to, subject, html: body }), | |
| }); | |
| return { sent_to: to, status: res.status }; | |
| } | |
| ``` | |
| ### `f/notifications/send_order_confirmation.ts` — uses it both ways | |
| ```typescript | |
| import * as wmill from "windmill-client"; | |
| // Option A: relative import — inlined, same job | |
| import { main as sendEmail } from "/f/common/send_email.ts"; | |
| export async function main(order_id: string, customer_email: string, total: number) { | |
| // Direct call via relative import (runs inline) | |
| await sendEmail( | |
| customer_email, | |
| `Order #${order_id} confirmed`, | |
| `<p>Your order of <b>$${total}</b> has been confirmed.</p>` | |
| ); | |
| // Option B: wmill.runScript — runs as a separate child job | |
| await wmill.runScript("f/common/send_email", { | |
| to: "warehouse@company.com", | |
| subject: `New order #${order_id}`, | |
| body: `<p>Please fulfill order #${order_id} ($${total}) for ${customer_email}.</p>`, | |
| }); | |
| return { order_id, notified: [customer_email, "warehouse@company.com"] }; | |
| } | |
| ``` | |
| --- | |
| ## Key Differences | |
| | | Relative import | `wmill.runScript` | | |
| |---|---|---| | |
| | **Execution** | Inlined in the same job | Spawns a separate child job | | |
| | **Logging** | One combined log | Each call gets its own run in the UI | | |
| | **Retries/timeout** | Shares parent's | Has its own | | |
| | **Use when** | You want speed + simplicity | You want visibility, independent retries, or to call across languages | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment