Render Workflows | Render

Render Workflows

Run thousands of parallel tasks with zero ops overhead. Scale seamlessly, retry automatically, and debug with full visibility.

Early access to Python and TypeScript SDKs begins soon.

@task
async def analyze_documents(file_paths: list[str]):
  files = await get_files(file_paths)
  results = await asyncio.gather(
    *[summarize_with_llm(path) for path in files]
  )
  return results

@task(
  options=Options(
    retry=Retry(max_retries=3, factor=2)
  )
)
def summarize_with_llm(path: str) -> dict:
  text = read_file(path)
  return call_llm_for_summary(text)

Smarter background jobs, right on queue

Model your batch processes and agentic workloads as composable tasks. Branch, retry, and fan out with ease.

SDK-first

Use lightweight TypeScript and Python SDKs to define tasks in your code with clean, declarative syntax. No DSLs or YAML required.

Queue-based autoscaling

Worker pools scale in seconds to handle bursty workloads. Scale down to zero when the task queue is empty.

Durable execution

Automatically retry failed tasks and surface failure patterns. Restore from stateful checkpoints without losing work.

Complete observability

Track, debug, and monitor runs in real time. Visualize bottlenecks in parallel runs with built-in instrumentation.

Your stack's elastic execution engine

Workflow steps are queued and scheduled on workers that spin up on demand. You define the jobs, and Render’s engine handles the distribution.

Engineered for your most demanding workloads

Dispatch entire fleets of long-lived, stateful compute—perfect for AI agents, ETL pipelines, and event-driven architectures.

Durable

Automatic retries

Avoid hitting rate limits with exponential backoff.

Stateful checkpointing

Restore to your last healthy state after an interruption.

Idempotent execution

Avoid duplicated work, even across retries.

Scalable

Fan out in seconds

Spin up hundreds or even thousands of workers when your queue spikes.

Run for hours

Go beyond 15-minute serverless limits—tasks can stay active for a day or more.

Scale to zero

Workers automatically spin down when there’s nothing to work on. Only pay for what you use.

Effortless

Drop-in libraries

Start running with just a few lines of code—no heavy frameworks or steep learning curve.

Local dev support

Iterate on your machine, then scale on ours.

First-class observability

View per-task logs, retries, and timelines.

Declaratively distributed

Express tasks as functions in Python, TypeScript, or Go. Render takes it from there: provisioning, monitoring, retries, and more.

@task
async def query_llms_and_evaluate(prompt: str) -> str:
  # Query 3 LLMs in parallel using model names
  model_configs = [
    {"provider": "openai", "model": "gpt-5"},
    {"provider": "anthropic", "model": "claude-opus-4"},
    {"provider": "google", "model": "gemini-2.5-pro"},
  ]
  responses = await asyncio.gather(
    *[query_llm(cfg["provider"], cfg["model"], prompt) for cfg in model_configs]
  )

# Have a 4th LLM evaluate and select the best response
  return await select_best_result(responses)

@task(
  options=Options(
    retry=Retry(max_retries=3, wait_duration_ms=5000, factor=2)
  )
)
async def query_llm(provider: str, model_name: str, prompt: str) -> str:
  providers = {
    "openai": ChatOpenAI,
    "anthropic": ChatAnthropic,
    "google": ChatGoogleGenerativeAI,
  }
  # Construct the appropriate LLM client based on provider
  llm = providers[provider](model=model_name)
  response = await llm.ainvoke([HumanMessage(content=prompt)])
  return response.content

@task(
  options=Options(
    retry=Retry(max_retries=2, wait_duration_ms=1000, factor=1.5)
  )
)
async def select_best_result(responses: list[str]) -> str:
  evaluator = ChatOpenAI(model="gpt-5")
  eval_prompt = (
    "Which response is best?\n\n    + " +
    "\n".join(f"{i}: {{r}}" for i, r in enumerate(responses))
  )
  evaluation = await evaluator.ainvoke([HumanMessage(content=eval_prompt)])
  return evaluation.content

Ready to queue up?

Workflows are launching soon. Request early access and help shape the future of background orchestration.