• Docs
  • Changelog
Sign in
Get started
    • Home
    • Your first deploy
    • Free instances
    • Platform features by plan
    • Use with coding agents
    • FAQ
    • Templates
      • Migrate from…
        • Heroku
        • Railway
    • Compute plans
    • SandboxesBeta
      • Service types
        • Which to use?
        • Static sites
        • Web services
        • Private services
        • Background workers
        • Cron jobs
        • Workflows
        • Multi-service architectures
      • Data storage
        • Render Postgres
        • Render Key Value (Redis®-compatible)
        • Persistent disks
    • How deploys work
    • Supported languages
    • Git providers (GitHub, etc.)
    • Build pipeline
    • Deploy hooks
    • Monorepo support
    • Troubleshooting deploys
      • Previewing changes
        • Single-service previews
        • Preview environments (multi-service)
      • Docker deploys
        • Overview
        • Deploy a registered image
        • Using secrets
      • Runtime
        • Native runtimes
        • Environment variables & secrets
        • Default environment variables
    • Intro to sandboxes
    • Limits
      • How to…
        • Create & configure sandboxes
        • Execute commands
        • Manage files
        • Manage snapshots
      • Use with…
        • Claude Managed Agents
        • Cursor Cloud Agents
        • OpenAI Agents API
      • SDK/CLI reference
        • TypeScript SDK
        • Python SDK
        • CLI commands
    • Intro to workflows
    • Tutorial
    • Limits & pricing
      • How to…
        • Define tasks
        • Define flowsNew
        • Trigger runs
        • Develop locally
      • SDK reference
        • TypeScript SDK
        • Python SDK
      • Example workflows
        • TypeScript examples
        • Python examples
    • Overview
    • Create & connect
    • Database credentials
    • Extensions
    • Version upgrades
    • Logical replication
    • Legacy instance types
      • Database recovery
        • Recovery & backups
        • High availability
      • Database performance
        • Read replicas
        • Connection pooling
        • Admin apps
        • Repacking tables
        • Troubleshooting performance
    • Regions
    • Inbound IP rules
    • Edge caching
    • WebSockets
    • TLS certificates
      • Custom domains
        • Overview
        • Cloudflare
        • Namecheap
        • Other DNS providers
      • Internal traffic
        • Private network
        • Private links
      • Outbound traffic
        • Default IP ranges
        • Dedicated IP addresses
        • Outbound bandwidth
        • Handling network changes
      • Static site config
        • Custom response headers
        • Redirects & rewrites
    • The Render Dashboard
    • SSH / Shell access
    • Projects & environments
      • Service actions
        • Scaling
        • Rollbacks
        • Maintenance mode
        • One-off jobs
      • Infrastructure as code
        • Blueprints overview
        • render.yaml reference
        • Terraform provider
    • In-dashboard metrics
    • Health checks
    • Uptime best practices
      • Logging
        • In-dashboard logs
        • Log streams (syslog/HTTPS)
      • OpenTelemetry (OTel) metrics
        • Provider setup
        • Metrics reference
      • Notifications
        • Webhooks
        • Email / Slack
    • MCP Server
      • Render CLI
        • Overview
        • Command reference
      • REST API
        • Overview
        • API reference
      • Third-party connections
        • OIDC support
        • Datadog
    • Workspaces, members, & roles
    • Login settings
    • Audit logs
      • Organizations
        • Overview
        • SAML SSO
    • DDoS protection
    • Platform maintenance
      • Compliance
        • Overview
        • HIPAA (US health data)
        • HIPAA best practices
        • Shared responsibility model
        • Pentest policy
    • Heroku vs Render
    • Vercel vs Render

Defining Tasks

Specify units of work to run on Render.

After you create your first workflow, you can start defining tasks for it. This article describes supported syntax and configuration options.

First: Install the Render SDK

The Render SDK is currently available for TypeScript and Python.

SDKs for additional languages are planned for future releases.

The Render SDK is required to define and register workflow tasks.

From your TypeScript project directory:

(Or pnpm install, bun add, etc.)

If you already have the SDK installed, make sure you're using version 1.7.0 or later:

After installing, make sure @renderinc/sdk is listed as a dependency in your package.json file at version ^1.7.0 or later.

From your Python project directory:

If you already have the SDK installed, make sure you're using version 1.7.0 or later:

After installing, make sure to add render>=1.7.0 as a dependency in your application's requirements.txt, pyproject.toml, or equivalent.

Basic example

Let's start with a "minimum viable workflow" that defines a single task:

This includes everything required to define a workflow:

  1. We import the task function and TaskContext type from the Render SDK.
  2. We call task(...) to register a function as a task (in this case, calculateSquare).
    • The first parameter to task(...) is an object containing configuration options (only name is required). For other supported options, see Configuring behavior.
    • The second parameter is the task function itself. This function must take a TaskContext object as its first argument (Render provides this object to each task run automatically).

This includes everything required to define a workflow:

  1. We import the Workflows class and TaskContext type from the Render SDK, then initialize a Workflows object as app.
  2. We apply the @app.task decorator to register a function as a task (in this case, calculate_square).
    • The decorator accepts a number of optional parameters (see Configuring behavior).
    • The task function must take a TaskContext object as its first argument (Render provides this object to each task run automatically).
  3. We call app.start() in our code's entry point.
    • On Render, this is what kicks off the task registration process and the execution of each run.

Organizing definitions

You can define your workflow's tasks across multiple files in your project repo:

In this example, definitions are distributed across two files: math-tasks.ts and text-tasks.ts. By setting your workflow's start command to run the JS output of index.ts, you ensure that all definitions are imported and registered.

In this example, definitions are distributed across two files: math_tasks.py and text_tasks.py.

To register all of your tasks, your workflow's entry point (commonly main.py) imports and incorporates the Workflows apps from each other file using the Workflows.from_workflows() method.

Naming tasks

For each task you define, provide a name that is unique across all tasks and flows in the workflow.

  • In TypeScript, registering another task or flow with the same name replaces the earlier definition.
  • In Python, duplicate names cause a registration error.

Function arguments

Every task function must take a TaskContext object as its first argument:

Render passes this object to each task run automatically.

A task function can define any number of additional arguments. This example task takes three additional arguments of different types:

You provide values for these arguments whenever you trigger or chain a task run.

You can set default values for arguments:

Argument format requirements

  • A task's argument types (and its return type) must be JSON-serializable.
    • Argument values are passed to a task run's instance as JSON, and a task run's result is returned as JSON.
  • The combined size of all arguments passed to a single task run cannot exceed 4 MB.
    • Otherwise, the run fails with an error.

Configuring behavior

Each task retry starts a new execution attempt with a fresh timeout. A run's total duration can therefore exceed its configured timeout.

Compute plan

By default, task runs execute on the Flex compute plan (up to 1 CPU, up to 4 GB RAM).

You can specify a different compute plan to use for a given task with the following syntax:

The following compute plans are available for workflow tasks:

Where are starter and standard?

The starter and standard compute plans from the Render Workflows beta have been discontinued in favor of flex.

  • The flex plan is now the default for any task that doesn't specify a different plan.
  • Any task that sets its plan to starter or standard now automatically uses flex instead.
  • The flex plan is billed according to your task run's actual RAM and CPU usage. This results in lower costs for most tasks that previously used starter or standard.
  • The flex plan provides up to the same CPU as standard and double the RAM.
CPURAMPlan IDLegacy Plan Name

Up to 1 CPU

Up to 4 GB

flex

24 GB

2c-4g

pro

28 GB

2c-8g

48 GB

4c-8g

pro_plus

416 GB

4c-16g

pro_max

832 GB

8c-32g

pro_ultra

See pricing details.

Timeout

By default, each execution attempt of a task run times out after 2 hours if its function hasn't returned yet. You can override this on a per-task basis to any value between 30 seconds and 24 hours.

Provide your task's timeout to task(...) via the timeoutSeconds option:

Provide your task's timeout to the @app.task decorator via the timeout_seconds parameter:

Retry settings

A task run can automatically retry if its initial attempt fails. Common failure cases include:

  • The task function raises an exception or throws an error.
  • The run times out.
  • The run exceeds its instance's compute limits.
  • The run's underlying instance encounters an unexpected error.

Each retry executes in its own instance, like the original attempt. If a run reaches its retry limit with no successful attempts, the run is marked as failed.

Default retry behavior

If you don't customize a task's retry behavior, it uses the following defaults:

  • Retry up to three times (i.e., four total attempts).
  • Wait one second before attempting the first retry.
  • Double the wait time after each retry (i.e., one second, two seconds, four seconds).

Customizing retries

You can customize retry behavior on a per-task basis. Every run of a task uses the same retry settings.

Provide retry settings with the following syntax:

This contrived example defines a task that "flips a coin" and raises an exception/error when it "flips tails", causing the attempt to fail. The run retries according to its settings, up to three times.

Chaining task runs

A task run can trigger additional task runs as part of its execution. These chained runs each execute in their own instance and return their result to their parent run:

run_agent()30s
gather_context()
execute_skills()
compose_response()
fetch_docs()
search_web()

All tasks in a run chain must belong to the same workflow service.

Chaining runs is an essential part of Render Workflows. It enables you to quickly fan out independent units of work across distributed compute, then roll up the entirety of that work into a unified result.

When to chain runs

Chaining runs is most useful when different parts of a larger job benefit from their own compute resources and/or retry boundaries.

For simpler, resource-light jobs, it can be more efficient to define the entirety of your logic in a single task.

How to chain runs

The TaskContext object passed to each task function provides a run method that you use to chain additional runs.

Let's look at an example:

The simple sumSquares task below chains two parallel runs of the calculateSquare task:

  • Chain a run by passing the corresponding task definition to ctx.run() (such as calculateSquare above).
    • You provide the run's arguments as additional parameters after the task definition.
    • You can await the Promise returned by ctx.run() to obtain the chained run's return value.
  • Any task function that chains runs should be defined as async.
    • Otherwise, it can't await the results of its chained runs.

The simple sum_squares task below chains two parallel runs of the calculate_square task:

  • Chain a run by passing the corresponding task definition to ctx.run() (such as calculate_square above).
    • You provide the run's arguments as additional parameters after the task definition.
    • You can await the result returned by ctx.run() to obtain the chained run's return value.
  • Any task function that chains runs should be defined as async.
    • Otherwise, it can't await the results of its chained runs.

Want to trigger a run of a task from a different workflow?

This requires instead using the Render SDK or Render API, as described in Running Workflow Tasks. Note that this is not tracked as a chaining relationship when visualizing task execution in the Render Dashboard.

Parallel runs

When chaining runs, you'll often want to chain multiple at once to distribute independent work. Common examples include processing batches of images or analyzing different sections of a large data set.

To chain parallel runs in TypeScript, use Promise.all, Promise.allSettled, or a similar concurrency utility.

In this example, the processPhotoUpload task chains a separate processImage run for each element in its imageUrls argument:

If you don't use Promise.all or a similar function, chained runs execute serially.

For example:

To chain parallel runs in Python, use asyncio.gather, asyncio.TaskGroup, or a similar concurrency utility.

In this example, the process_photo_upload task chains a separate process_image run for each element in its image_urls argument:

If you don't use asyncio.gather or a similar function, chained runs execute serially.

For example:

Serial execution is helpful when one run depends on the result of another. However, it can significantly slow execution for runs that are completely independent. Parallelize wherever your use case allows.

Defining Tasks
  • First: Install the Render SDK
  • Basic example
  • Organizing definitions
    • Naming tasks
  • Function arguments
    • Argument format requirements
  • Configuring behavior
    • Compute plan
    • Timeout
    • Retry settings
  • Chaining task runs
    • When to chain runs
    • How to chain runs
    • Parallel runs
All Systems Operational
© Render Inc. All rights reserved.