# Durability as code: Introducing Render Workflows

- Date: 2026-04-07T10:45:00.000Z
- Category: product
- Author: Vivek Ravishankar
- URL: https://render.com/blog/durability-as-code-introducing-render-workflows

*Build durable, long-running AI workflows and background jobs with an SDK. Now in beta for TypeScript and Python.*

---

Deploying background workloads for your agents and apps should be as simple as pushing the code.

Instead, running them reliably still means standing up your own queues, workers, state management, and retry infrastructure. 

We’re launching [Render Workflows](https://render.com/workflows) to help you build reliable, long-running processes like agent logic, data pipelines, and billing flows without making distributed systems your full-time job. 

Define tasks and chained logic in your TypeScript or Python code using the Render SDK, and trigger them from anywhere. Render handles the infrastructure to make your workflows low-latency, stateful, and resilient.

## Fully-managed execution

A Workflow service in Render is an all-in-one package of queuing, worker pools, state management, retry logic, and observability. You define processes as a collection of tasks in your code using the Render SDK, deploy your code as a Workflow service in Render, and Render handles execution whenever you trigger a task. 

For you, that means:

*Just write code.* Use the Render SDK to turn any function into a durable `task` with its own retry behavior. Like regular functions, you can chain tasks to define multi-step logic and parallel execution.

*Automatic infrastructure.* When you trigger a task, Render spins it up in its own isolated container within milliseconds and automatically serializes and transports args to containers for chained tasks.

*Parallel execution.* Parallelize heavy workloads across hundreds of concurrent containers. Render automatically handles scheduling and provisioning for tasks that are invoked in parallel.

*Cost scales to zero.* You only pay for the compute your tasks run on, prorated to the second. If you aren’t running any tasks, you aren’t paying anything. You can also define the compute plan for each task independently to optimize your spend for lighter and heavier tasks. 

*Run, observe, and debug in one place.* Your tasks run on a private network alongside your other Render services. You can see a unified view of metrics and logs for every task run in the Render dashboard. No glue code. No jumping between dashboards to debug a failed run.

## Define workflow tasks

Your workflow is a collection of tasks. Tasks are just as flexible as regular functions, but each can have its own retry logic, timeout, and compute plan. 

In TypeScript, you define tasks using the `task()` wrapper function. In Python, use the `@app.task` decorator:

**TypeScript**

```typescript
import { task } from '@renderinc/sdk/workflows'

const generateCode = task({
  name: 'generateCode',
 }, async function (plan: AppPlan, model: string) {
  // generate code based on AppPlan with selected model, parse response into files
})
```

**Python**

```python
from render_sdk import Workflows 
app = Workflows()

@app.task  # Python SDK infers task name from function name
async def generate_code(plan: dict, model: str):
    # generate code based on AppPlan with selected model, parse response into files
```

To configure retry behavior, timeout, and compute for your task, add them directly to the task definition:

**TypeScript**

```typescript
import { task } from '@renderinc/sdk/workflows'

const generateCode = task({
  name: 'generateCode',
  retry: {
    maxRetries: 3, // retry up to 3 times
    waitDurationMs: 1000, // wait 1s before first retry
    backoffScaling: 1.5 // exponential backoff for subsequent retries
  },
  timeoutSeconds: 60, // configurable up to 24 hours
  plan: 'starter' // configurable up to 'Pro Ultra' (8 CPU / 32GB RAM)
 }, async function (plan: AppPlan, model: string) {
  // generate code based on AppPlan with selected model, parse response into files
})

```

**Python**

```python
from render_sdk import Workflows, Retry
app = Workflows()
@app.task(  # Python SDK infers task name from function name
    retry=Retry(
        max_retries=3, # retry up to 3 times
        wait_duration_ms=1000, # wait 1s before first retry
        backoff_scaling=1.5 # exponential backoff for subsequent retries
    ),
    timeout_seconds=60, # configurable up to 24 hours
    plan="standard" # configurable up to 'Pro Ultra' (8 CPU / 32GB RAM)
)
async def generate_code(plan: dict, model: str):
    # generate code based on AppPlan with selected model, parse response into files
```

Workflows are most useful when you need to run complex processes made up of many sequential and parallel tasks. You can build that logic by chaining tasks just like you would normal functions. 

For example, an agent that generates code for a web app may need a loop that chains multiple LLM calls and sandboxes to generate, validate, and display a preview to the user after a prompt:

**TypeScript**

```typescript
const generationLoop = task({ name: 'generationLoop' },
  async function (prompt: string, userId: string, startingSnapshotId?: string) {
    // create a plan from the prompt (or modify existing plan if iterating)
    let plan = await planStructure(prompt, startingSnapshotId)
    let code = await generateCode(plan)
    let sandboxId = plan.sandboxId
    const errors: BuildError[] = []

    // build → check → revise until it works (max 3 attempts)
    while (errors.length < 3) {
      const build = await buildInSandbox(code, sandboxId)
      sandboxId = build.sandboxId
      if (build.success) {
        // deliver preview to user and save state in parallel
        await Promise.all([
          pushPreview(userId, build.previewUrl),
          saveSnapshot(sandboxId, code)
        ])
        return
      }
      // build failed: revise plan and fix code
      errors.push(build.errors)
      plan = await revisePlan(plan, errors)
      code = await fixCode(code, plan, build.errors)
    }
    // all attempts failed: explain what went wrong
    return diagnoseFailure(prompt, errors)
  }
)

const planStructure = task({ name: 'planStructure' }, ...) // prompt + optional snapshot → plan
const generateCode = task({ name: 'generateCode' }, ...) // plan → application code
const buildInSandbox = task({ name: 'buildInSandbox' }, ...) // install, compile, run
const revisePlan = task({ name: 'revisePlan' }, ...) // adjust plan from errors
const fixCode = task({ name: 'fixCode' }, ...) // targeted code edits
const pushPreview = task({ name: 'pushPreview' }, ...) // send preview URL to user
const saveSnapshot = task({ name: 'saveSnapshot' }, ...) // version current artifacts
const diagnoseFailure = task({ name: 'diagnoseFailure' }, ...) // explain failure to user 
```

**Python**

```python
@app.task
async def generation_loop(prompt: str, user_id: str, starting_snapshot_id: str = None):
    # create a plan from the prompt (or modify existing plan if iterating)
    plan = await plan_structure(prompt, starting_snapshot_id)
    code = await generate_code(plan)
    sandbox_id = plan.sandbox_id
    errors = []

    # build → check → revise until it works (max 3 attempts)
    while len(errors) < 3:
        build = await build_in_sandbox(code, sandbox_id)
        sandbox_id = build.sandbox_id
        if build.success:
            # deliver preview to user and save state in parallel
            await asyncio.gather(
                push_preview(user_id, build.preview_url),
                save_snapshot(sandbox_id, code)
            )
            return
        # build failed: revise plan and fix code
        errors.append(build.errors)
        plan = await revise_plan(plan, errors)
        code = await fix_code(code, plan, build.errors)

    # all attempts failed: explain what went wrong
    return await diagnose_failure(prompt, errors)

@app.task
async def plan_structure(...): ... # prompt + optional snapshot → plan
@app.task
async def generate_code(...): ... # plan → application code
@app.task
async def build_in_sandbox(...): ... # install, compile, run
@app.task
async def revise_plan(...): ... # adjust plan from errors
@app.task
async def fix_code(...): ... # targeted code edits
@app.task
async def push_preview(...): ... # send preview URL to user
@app.task
async def save_snapshot(...): ... # version current artifacts
@app.task
async def diagnose_failure(...): ... # explain failure to user 
```

## Trigger tasks

With your tasks defined, you can deploy your code as a Workflow service on Render and start triggering tasks.

Typically, you’ll trigger tasks directly from your application code for other services on Render:

**TypeScript**

```typescript
import { Render } from '@renderinc/sdk'
const render = new Render()
const run = await render.workflows.runTask(
  'my-workflow/generationLoop',
  [prompt, userId, startingSnapshotId]
)
```

**Python**

```python
from render_sdk import RenderAsync

render = RenderAsync()
run = await render.workflows.start_task(
    "my-workflow/generation_loop",
    [prompt, user_id, starting_snapshot_id]
)
```

You can also trigger tasks from external services using the Render API or manually through the Render Dashboard.

## Distributed execution, central observability

Because Render handles all of the infrastructure for your workflows from start to finish, it gives you a unified view of traces, metrics, and logs across every executed task without any additional setup. 

You can analyze the reliability of individual tasks, monitor for opportunities to optimize compute, and debug failed runs through a single dashboard or CLI. 

[image: Observe workflows with a unified dashboard]

## Workflow examples and agent skills

To see some of the systems you can implement with Workflows, explore our curated examples in the [Workflows Playground](https://render.com/workflows/playground?example=hello-world&lang=typescript). You can also spin up an example workflow locally with the Render CLI: 

```bash
render workflows init
```

Workflows are defined entirely in your code using an idiomatic SDK, so Claude Code, Cursor, Codex, and other agents can reason about them and build them for you.

To teach your agents how to build and debug workflows, install the workflows agent skill:

```bash
render skills install render-workflows
```

## For the future of intelligent apps

[Workflows](https://render.com/workflows) are designed to let you build reliable, scalable, intelligent apps by just writing code. 

AI agents need infrastructure shaped for long-running, stateful workloads. They depend on complex, multi-service agent loops, data pipelines, and other orchestration patterns that allow individual tasks to fail, retry, and parallelize gracefully. 

With Workflows, you define that logic in your codebase and deploy it instantly, keeping you focused on building your product rather than infrastructure.

Over the course of beta, we’ll be extending Workflows to expand the breadth of processes you can build:

* Vertically autoscale task compute to optimize performance and cost  
* Kick off tasks via cron  
* Pause and resume workflows  
* Checkpoint state to recover from interruptions  
* Additional language support

You can start building workflows today with the TypeScript and Python SDKs. Read the [Workflows Docs](https://render.com/docs/workflows) to learn more.
