The Render CLI ships an init command that drops a working Workflow project on your disk in a single step. You’ll use it, then poke at what it generated.
1. Install the Render CLI
You need version 2.11.0 or newer for the workflow commands. Check first:
$render --versionrender version 2.11.0 (or newer)
If the command isn’t found or the version is too old, install or upgrade:
brew install render# or upgrade an existing installbrew upgrade rendercurl -fsSL https://raw.githubusercontent.com/render-oss/cli/main/bin/install.sh | shDownload the executable from the CLI releases page and put it on your PATH.
2. Scaffold the project
Run init from the directory where you want a new workflows/ folder:
$render workflows init? Choose a language: (Use arrow keys)> PythonTypeScript
Pick your language, accept the defaults, and the CLI will:
- Create a workflows/ directory A self-contained folder with its own dependency file - separate from anything you already have at the project root.
- Drop in a starter task A
calculateSquaretask plus a couple of more advanced examples (fan-out, retries) so you have something to copy from. - Print next steps Including the local-dev command for the language you picked.
3. What it generated
from render_sdk import Workflows, Retryimport asyncioimport random
app = Workflows()
@app.taskdef calculate_square(a: int) -> int: return a * a
@app.taskasync def sum_squares(a: int, b: int) -> int: result1, result2 = await asyncio.gather( calculate_square(a), calculate_square(b), ) return result1 + result2
@app.task( retry=Retry(max_retries=3, wait_duration_ms=1000, backoff_scaling=1.5))def flip_coin() -> str: if random.random() < 0.5: raise Exception("Flipped tails! Retrying.") return "Flipped heads!"
if __name__ == "__main__": app.start()render_sdkInstall the SDK into a venv so the editor and the dev server can find it:
cd workflowspython -m venv .venv && source .venv/bin/activatepip install -r requirements.txtcd ..import { task } from "@renderinc/sdk/workflows";
const calculateSquare = task( { name: "calculateSquare" }, function calculateSquare(a: number): number { return a * a; },);
const sumSquares = task( { name: "sumSquares" }, async function sumSquares(a: number, b: number): Promise<number> { const [result1, result2] = await Promise.all([ calculateSquare(a), calculateSquare(b), ]); return result1 + result2; },);
const flipCoin = task( { name: "flipCoin", retry: { maxRetries: 3, waitDurationMs: 1000, backoffScaling: 1.5 }, }, function flipCoin(): string { if (Math.random() < 0.5) { throw new Error("Flipped tails! Retrying."); } return "Flipped heads!"; },);{ "scripts": { "start": "tsx index.ts" }, "dependencies": { "@renderinc/sdk": "^0.4.1" }, "devDependencies": { "tsx": "^4.20.2" }}Install dependencies:
npm install --prefix workflowsThe TypeScript SDK registers tasks via the task(...) calls at module scope and auto-starts the server when imported by the Render runtime (via the RENDER_SDK_SOCKET_PATH environment variable). Python’s Workflows() is an explicit object, so you call app.start() yourself inside if __name__ == "__main__":.
4. Sanity-check what registered
The CLI ships a local task server. Start it in one terminal and list tasks in another.
render workflows dev -- python workflows/main.pyrender workflows dev -- npx tsx workflows/index.tsrender workflows tasks list --localYou should see three tasks: calculateSquare (or calculate_square), sumSquares (or sum_squares), and flipCoin (or flip_coin). If you don’t, the most common cause is the dev server not being started yet or the --local flag being missing.
What you learned
- Installed/verified the Render CLI 2.11.0+
- Generated a workflows/ directory with `render workflows init`
- Started a local task server and confirmed three tasks registered