# Render Workflows — Rapidly spin up chains of long-running tasks on distributed compute. > *Render Workflows is in public beta.* > > During the beta, bugs or changes in API/SDK behavior are possible as we continue refining the product. We welcome any and all feedback at *workflows-feedback@render.com*. Use *Render Workflows* to rapidly distribute computational work across multiple independent instances: Workflows overview Workflows are perfect for use cases that benefit from high-performance, distributed execution, such as AI agents, ETL pipelines, and data processing. ## How it works 1. Using the Render SDK, you can mark functions in your code as *tasks*. **TypeScript** Here's minimal TypeScript for defining a task named `calculateSquare`. First import `task` from the SDK, then call it with an options object and your task function: ```typescript:index.ts import { task } from '@renderinc/sdk/workflows' const calculateSquare = task( { name: 'calculateSquare' }, function calculateSquare(a: number): number { return a * a } ) ``` **Python** Here's minimal Python for defining a task named `calculate_square`. First initialize a `Workflows` app, then apply the `@app.task` decorator: ```python:main.py from render_sdk import Workflows app = Workflows() @app.task def calculate_square(a: int) -> int: return a * a if __name__ == "__main__": app.start() ``` 2. In the Render Dashboard, you create a workflow service and link the repo containing your task definitions. Render automatically *registers* your defined tasks: [image: Viewing registered tasks in the Render Dashboard] 3. You can now trigger *runs* of your registered tasks from anywhere (web apps, agents, etc.) using the Render SDK or API. **TypeScript** Here's minimal TypeScript for triggering a run of `calculateSquare` and passing the argument `2`: ```typescript:client_app.ts import { Render } from '@renderinc/sdk' const render = new Render() const startedRun = await render.workflows.startTask( 'my-workflow/calculateSquare', [2], ) const finishedRun = await startedRun.get() console.log(finishedRun.results) ``` **Python (async)** Here's minimal async Python for triggering a run of `calculate_square` and passing the argument `2`: ```python:client_app.py from render_sdk import RenderAsync render = RenderAsync() started_run = await render.workflows.start_task( "my-workflow/calculate_square", [2], ) finished_run = await started_run print(finished_run.results) ``` **Python (sync)** Here's minimal synchronous Python for triggering a run of `calculate_square` and passing the argument `2`: ```python:client_app.py from render_sdk import Render render = Render() finished_run = render.workflows.run_task( "my-workflow/calculate_square", [2], ) print(finished_run.results) ``` 4. Render spins up each triggered run in its own instance. - This usually takes less than a second. 5. A run can trigger _additional_ runs simply by calling the corresponding task function. This is called *run chaining*. **TypeScript** Below, the `sumSquares` task chains two parallel runs of `calculateSquare`: ```typescript:index.ts 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 { const [result1, result2] = await Promise.all([ calculateSquare(a), calculateSquare(b) ]) return result1 + result2 } ) ``` **Python** Below, the `sum_squares` task chains two parallel runs of `calculate_square`: ```python:main.py from render_sdk import Workflows import asyncio app = Workflows() @app.task def calculate_square(a: int) -> int: return a * a @app.task async def sum_squares(a: int, b: int) -> int: result1, result2 = await asyncio.gather( calculate_square(a), calculate_square(b) ) return result1 + result2 ``` Runs execute alongside other Render service types, enabling fast and safe communication over your private network. ## Core features | Feature | Description | | --- | --- | | *Automatic queuing and orchestration* | Render coordinates the entire task run lifecycle for you, from queuing to spin-up to deprovisioning. | | *Long-running execution* | Each task run can execute for up to 24 hours. | | *Configurable retry logic* | Define [retry behavior](/workflows-defining#retry-logic) for each task in the event of a failed run, with exponential backoff. | | *Configurable timeout* | Specify a [timeout](/workflows-defining#timeout) for runs of each task, from 30 seconds to 24 hours. | | *Configurable compute specs* | Specify which [instance type](/workflows-defining#instance-type-compute-specs) to use for runs of each task. | | *Workflow-wide defaults* | Set the default retry logic, timeout, and instance type for all tasks in your workflow (and optionally override per task). | | *Execution observability* | Track the progress and status of active and completed runs in the Render Dashboard. | | *Outbound networking* | Runs can initiate network connections over both the public internet and your private network. Runs cannot receive _incoming_ network connections. | | *Unified SDK* | Install a single lightweight SDK both to register tasks and to trigger runs from your code. > *The Render SDK is currently available for [TypeScript](/workflows-sdk-typescript) and [Python](/workflows-sdk-python).* SDKs for additional languages are planned for future releases. | ### Beta limitations We'll address these limitations in future releases following beta: - Workflows currently only support TypeScript and Python for defining tasks. - SDKs for other languages are planned for future releases. - Workflows do not provide built-in support for automatically triggering runs on a schedule. - To schedule runs, you can create a [cron job](cronjobs) that runs your tasks on the desired schedule. - If a workflow belongs to a [network-isolated environment](projects#blocking-cross-environment-traffic), its runs _cannot_ communicate with other services in that environment over its private network. - Workflows do not yet support running tasks on [HIPAA-compliant](hipaa-compliance) hosts. - To prevent accidental PHI exposure, it is not currently possible to create new workflows in a HIPAA-enabled workspace. - If you enable HIPAA compliance for a workspace that already has workflows, *do not process PHI in your workflows.* ## Get started Now that you know the basics, you're ready to [create your first workflow!](/workflows-tutorial) ## Billing See [Limits and Pricing for Render Workflows](/workflows-limits). ## FAQ ###### How do I get started with Render Workflows? Get started with [Your First Workflow](/workflows-tutorial). ###### Which languages can I use to define workflow tasks? The Render SDK is available for [TypeScript](/workflows-sdk-typescript) and [Python](/workflows-sdk-python). SDKs for additional languages are planned for future releases. ###### Can I trigger task runs without using the Render SDK? *Yes.* For languages without Render SDK support, you can trigger runs by calling the Render API directly. For details, see [Triggering Task Runs](/workflows-running). ###### Can my task runs receive incoming network connections? *No.* Similar to background workers, task runs must initiate any required network connections. --- ##### Appendix: Glossary definitions ###### task A function you can execute on its own compute as part of a *workflow*. Each execution of a task is called a *run*. Related article: https://render.com/docs/workflows-defining.md ###### run A single execution of a workflow *task*. A run spins up in its own *instance*, executes, returns a value, and is deprovisioned. Related article: https://render.com/docs/workflows-running.md ###### instance A virtual machine that runs your service's code on Render. You can select from a range of *instance types* with different compute specs. ###### run chaining Triggering a new *task run* by calling its function from an in-progress run. All runs in a chain belong to the same *workflow*. Related article: https://render.com/docs/workflows-defining.md ###### service type When you deploy code on Render, you select a *service type* based on the capabilities you need. For example, you create a *web service* to host a dynamic web app at a public URL. Related article: https://render.com/docs/service-types.md ###### private network Your Render services in the same *region* can reach each other without traversing the public internet, enabling faster and safer communication. Related article: https://render.com/docs/private-network.md ###### background worker Deploy this *service type* to continuously run code that does not receive incoming requests. Ideal for processing jobs from a queue. Related article: https://render.com/docs/background-workers.md