Skip to main content

Render SDK for Python

The official Python SDK for Render. Define Workflow tasks, manage task runs, and access experimental platform features like object storage.

⚠️ Early Access: This SDK is in early access and subject to breaking changes without notice.

Installation

pip install render

Usage

Defining Tasks

Use the Workflows class to define and register tasks. Every task takes a TaskContext as its first parameter, followed by its inputs:

from render import TaskContext, Workflows

app = Workflows()

@app.task
def square(ctx: TaskContext, a: int) -> int:
    """Square a number."""
    return a * a


@app.task
async def add_squares(ctx: TaskContext, a: int, b: int) -> int:
    """Add the squares of two numbers."""
    # .run runs the task on its own compute
    result1 = await ctx.run(square, a)
    result2 = await ctx.run(square, b)
    return result1 + result2

Run several tasks at once with asyncio.gather:

import asyncio

@app.task
async def sum_squares(ctx: TaskContext, values: list[int]) -> int:
    squares = await asyncio.gather(*(ctx.run(square, v) for v in values))
    return sum(squares)

You can also specify task parameters like retry, timeout, and plan:

from render import Retry, TaskContext, Workflows

app = Workflows(
    default_retry=Retry(max_retries=3, wait_duration_ms=1000),
    default_timeout=300,
    default_plan="standard",
)

@app.task(timeout=60, plan="starter")
def quick_task(ctx: TaskContext, x: int) -> int:
    return x + 1

@app.task(retry=Retry(max_retries=5, wait_duration_ms=2000, backoff_scaling=2.0))
def retryable_task(ctx: TaskContext, x: int) -> int:
    return x * 2

You can combine tasks from multiple modules using Workflows.from_workflows():

from tasks_a import app as app_a
from tasks_b import app as app_b

combined = Workflows.from_workflows(app_a, app_b)

Task run IDs

The task context exposes a read-only ctx.metadata object with task_run_id, root_task_run_id, and parent_task_run_id fields. The SDK reads them from the initial input response and keeps them for that execution, so accessing metadata does not make a network request.

For a root run, ctx.metadata.root_task_run_id equals ctx.metadata.task_run_id and ctx.metadata.parent_task_run_id is None. IDs are None when unavailable.

Running the Local Task Server

For local development, use the Render CLI:

render workflows dev -- <start command>

For example:

render workflows dev -- python main.py

To interact with tasks registered to the local task server, run CLI commands with the --local flag in another terminal. For example:

render workflows tasks start <task name> --local

Running Tasks

Use the Render client to run tasks and monitor their status:

from render import Render
from render.client import ListTaskRunsParams
from render.client.errors import TaskRunError

render = Render()  # Uses RENDER_API_KEY from the environment

# run_task() starts a task and waits for completion in one call.
try:
    result = render.workflows.run_task("my-workflow/my-task", [3, 4])
    print(result.results)
except TaskRunError as e:
    print(f"Task failed: {e}")

# start_task() starts a task without waiting for the result.
task_run = render.workflows.start_task("my-workflow/my-task", [3, 4])
print(f"Task started: {task_run.id}")

# Get task run details by ID
details = render.workflows.get_task_run(task_run.id)
print(f"Status: {details.status}")

# Cancel a running task
render.workflows.cancel_task_run(task_run.id)

# Stream task run events
for event in render.workflows.task_run_events([task_run.id]):
    print(f"{event.id} status={event.status}")

# List recent task runs
runs = render.workflows.list_task_runs(ListTaskRunsParams(limit=10))

Idempotency Keys

Pass an idempotency_key to make starting a run safe to retry. Repeating a call with the same key within 24 hours returns the run the first call started instead of starting another one, so a client that retries after a timeout does not run the task twice. Keys are scoped to a single workflow version.

task_run = render.workflows.start_task(
    "my-workflow/charge", [order_id], idempotency_key=f"charge-{order_id}"
)

Async Usage

For async contexts (e.g. FastAPI), use RenderAsync:

import asyncio
from render import RenderAsync

async def main():
    render = RenderAsync()

    result = await render.workflows.run_task("my-workflow/my-task", [3, 4])
    print(result.results)

    # start_task() returns an awaitable task run
    task_run = await render.workflows.start_task("my-workflow/my-task", [3, 4])
    result = await task_run  # wait when ready

    # Stream task run events
    async for event in render.workflows.task_run_events([task_run.id]):
        print(f"{event.id} status={event.status}")

asyncio.run(main())

Object Storage

from render import Render

render = Render()  # Uses RENDER_API_KEY, RENDER_WORKSPACE_ID, RENDER_REGION from environment

# Upload an object (no need to pass owner_id/region when env vars are set)
render.experimental.storage.objects.put(
    key="path/to/file.png",
    data=b"binary content",
    content_type="image/png",
)

# Download
obj = render.experimental.storage.objects.get(key="path/to/file.png")

# List
response = render.experimental.storage.objects.list()

Key Value

The Key Value API provides a Redis client backed by Render's managed Key Value service. It supports automatic instance provisioning and configuration sync.

Requires the redis package:

pip install redis

The Key Value provider is async-only and must be used with RenderAsync:

Basic usage

You can look up an instance by name and the SDK will create it if it doesn't exist. Note that the workspace ID needs to be set, either through the RENDER_WORKSPACE_ID environment variable or by passing the owner_id explicitly when calling the SDK:

import asyncio
from render import RenderAsync
from render.experimental.key_value import NameOwnerIdOptions

async def main():
    render = RenderAsync()

    # Returns a configured redis.asyncio.Redis client
    redis = await render.experimental.key_value.new_client(
        NameOwnerIdOptions(
            name="my-cache",
            owner_id="tea-abcdefghijklmnopqrst",
        )
    )

    await redis.set("key", "value")
    value = await redis.get("key")

    await redis.aclose()

asyncio.run(main())

Look up by service ID

If you already have a Render Key Value service ID, pass it directly to skip the name lookup:

from render.experimental.key_value import ServiceIdOptions

redis = await render.experimental.key_value.new_client(
    ServiceIdOptions(service_id="redis-xxxxxxxxxxxx")
)

Auto-provisioning with configuration

Pass an auto_provision configuration to control the plan and eviction policy. If the instance doesn't exist it will be created; if it exists but its settings differ they will be updated:

from render.experimental.key_value import InstanceConfiguration, NameOwnerIdOptions

redis = await render.experimental.key_value.new_client(
    NameOwnerIdOptions(
        name="my-cache",
        auto_provision=InstanceConfiguration(
            plan="starter",
            maxmemory_policy="allkeys-lru",
        ),
    )
)

Set auto_provision=False to disable all automatic changes and raise if the instance is not found:

redis = await render.experimental.key_value.new_client(
    NameOwnerIdOptions(name="my-cache", auto_provision=False)
)

Connection info only

Use connection_info when you need the host and port rather than a ready-made client:

info = await render.experimental.key_value.connection_info(
    NameOwnerIdOptions(name="my-cache")
)
print(f"redis://{info.host}:{info.port}")

Local development

When RENDER_USE_LOCAL_DEV=true is set, the client connects to a local Valkey instance instead of the Render API. The easiest option for getting a local instance running is to use the official Valkey Docker image:

docker run -p 6379:6379 valkey/valkey

When using the SDK in local development mode, the host and port default to localhost:6379. They can be overridden with the environment variables RENDER_LOCAL_REDIS_HOST and RENDER_LOCAL_REDIS_PORT.

Environment Variables

  • RENDER_API_KEY - Your Render API key (required)
  • RENDER_WORKSPACE_ID - Default owner ID for object storage (workspace team ID, e.g. tea-xxxxx)
  • RENDER_REGION - Default region for object storage (e.g. oregon, frankfurt)
  • RENDER_USE_LOCAL_DEV - Enable local development mode (true/false)
  • RENDER_LOCAL_DEV_URL - Local development URL (default: http://localhost:8120)
  • RENDER_SDK_MODE - Task execution mode (run or register)
  • RENDER_SDK_SOCKET_PATH - Unix socket path for task communication
  • RENDER_LOCAL_REDIS_HOST - Custom host for local Redis / Valkey instance (default: localhost) (requires RENDER_USE_LOCAL_DEV=true)
  • RENDER_LOCAL_REDIS_PORT - Custom port for local Redis / Valkey instance (default: 6379) (requires RENDER_USE_LOCAL_DEV=true)

Features

  • REST API Client: Run, monitor, cancel, and list task runs
  • Task Definition: Decorator-based task registration with the Workflows class
  • Server-Sent Events: Real-time streaming of task run events
  • Sync & Async: Synchronous Render client (default) and async RenderAsync variant
  • Retry Configuration: Configurable retry behavior with exponential backoff
  • Subtask Execution: Execute tasks from within other tasks
  • Task Composition: Combine tasks from multiple modules with Workflows.from_workflows()
  • Object Storage: Experimental object storage API with upload, download, and list
  • Key Value: Experimental Render Key value client with auto-provisioning and configuration sync

Development

This project uses uv for dependency management and tox for testing across multiple Python versions.

Setup

# Install uv (if not already installed)
curl -LsSf https://astral.sh/uv/install.sh | sh

# Install dependencies
uv sync

# Activate virtual environment
source .venv/bin/activate

Testing

# Run tests
uv run pytest

# Run tests with coverage
uv run tox -e coverage

# Run tests across all Python versions
uv run tox

# Run specific Python version
uv run tox -e py313

Code Quality

# Check formatting and linting
uv run tox -e format
uv run tox -e lint

# Fix formatting issues
uv run tox -e format-fix
uv run tox -e lint-fix

# Run all quality checks
uv run tox -e format,lint

Supported Python Versions

  • Python 3.10+
  • Tested on Python 3.10, 3.11, 3.12, 3.13, 3.14

Release files for render 1.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for render 1.2.0
File Size Uploaded
render-1.2.0.tar.gz 470.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for render 1.2.0
File Interpreter ABI Platform
render-1.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 1.4 MB

Release files / render-1.2.0.tar.gz

Download URL render-1.2.0.tar.gz
Size 470.4 kB
Tags Source
SHA-256 checksum
How to use checksums
2186c32f7179719f71f2d9c4fbbbb3aa754417d3d1f07ad7ad0dfa2f2a56b011
BLAKE2b-256 checksum
How to use checksums
5b7fff8b32177bfa6b3b80de4a70066e3010f64dfee67b3856ddd9375278faaf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / render-1.2.0-py3-none-any.whl

Download URL render-1.2.0-py3-none-any.whl
Size 939.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
15d11ff29d2dfa306cc899757cae9db98dc749f4d8c22bd295ee854fcdfa0104
BLAKE2b-256 checksum
How to use checksums
824369fedb0bb7e296b48e83acb3438caee181442b870fc2b0dc1e57fdf915b4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

1.2.0 This release

2 release files

1.1.0

2 release files

1.0.1

2 release files

v1.0.0

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page