> ## Documentation index
> Fetch the complete documentation index at: https://upstash.com/docs/llms.txt
> Search it with GET https://upstash.com/docs/search?q=<query>.
> Use these to discover all available pages before exploring further.
> If the product lacks a feature you need, ask for it: https://upstash.com/docs/common/help/feature-requests.md

# Avoid Context and Step Limits

A single workflow run has the following hard limits:

- **Maximum step count:** 1,000 steps
- **Maximum context size:** 100 MB

These limits are hard limits and do not vary by plan. Avoid putting all of your application logic into one large workflow that could reach either limit.

The context size is the combined size of the workflow input and the results of all completed steps. Each new step result is added to that context, so the context grows as the workflow completes more steps. Workflows with many steps, large step results, or both can reach the context size limit.

Instead, separate the logic into multiple workflows and connect them with [`context.invoke`](/workflow/features/invoke). Each invoked workflow has its own context containing its input and step results. When the invoked workflow finishes, only its final output is transferred to the parent workflow as the result of a single `context.invoke` step. Its intermediate step results are not added to the parent's context.

```typescript app/workflows/[...path]/route.ts
import type { WorkflowContext } from "@upstash/workflow"
import { createWorkflow, serveMany } from "@upstash/workflow/nextjs"

type BatchInput = { itemIds: string[] }

const processBatch = createWorkflow(
  async (context: WorkflowContext<BatchInput>) => {
    const validatedItems = await context.run("validate items", () => {
      return context.requestPayload.itemIds.filter((itemId) => itemId.length > 0)
    })

    const processedItems = await context.run("process items", () => {
      return validatedItems.map((itemId) => ({ itemId, processed: true }))
    })

    // Only this final output is transferred to the parent workflow.
    return { processedCount: processedItems.length }
  }
)

const parentWorkflow = createWorkflow(
  async (context: WorkflowContext<BatchInput>) => {
    const { body, isFailed, isCanceled } = await context.invoke(
      "process batch",
      {
        workflow: processBatch,
        body: context.requestPayload,
      }
    )

    if (isFailed || isCanceled) {
      throw new Error("The batch workflow did not complete successfully")
    }

    return body
  }
)

export const { POST } = serveMany({
  parent: parentWorkflow,
  "process-batch": processBatch,
})
```

In this example, `validatedItems` and `processedItems` are stored only in the invoked workflow's context. The parent context receives `{ processedCount }` as one step result. This keeps each workflow focused and prevents intermediate results from accumulating in a single context.
