Skip to content

Commit 58720ef

Browse files
authored
feat: dynamic Actor memory (#2145)
This PR adds documentation for the recently released Dynamic Actor Memory feature. I also added backlinks from related documentation sections. More information in [spec](https://www.notion.so/Dynamic-default-Actor-memory-293f39950a2280b9aa34fa9cd07f52a4?source=copy_link) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Documents dynamic Actor memory with `defaultMemoryMbytes` (int or expression), updates related docs, and extends OpenAPI Actor definition. > > - **Docs**: > - **New**: Dynamic memory guide at `sources/platform/actors/development/actor_definition/dynamic_actor_memory/index.md` (expressions, helpers, limits, testing via NPM/CLI). > - **actor.json**: Example and reference for `defaultMemoryMbytes` (supports dynamic expression strings). > - **Running**: > - `input_and_output.md`: Info note explaining dynamic memory behavior and override via run option. > - `usage_and_resources.md`: Clarify memory can be omitted to use Actor default (may be dynamic) and restate constraints. > - **OpenAPI**: > - `apify-api/openapi/components/schemas/actors/ActorDefinition.yaml`: Add `defaultMemoryMbytes` (oneOf integer|string) with description. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 0305a25. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent fba02bc commit 58720ef

File tree

5 files changed

+266
-3
lines changed

5 files changed

+266
-3
lines changed

apify-api/openapi/components/schemas/actors/ActorDefinition.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ properties:
4242
dataset:
4343
type: object
4444
description: Defines the schema of items in your dataset, the full specification can be found in [Apify docs](https://docs.apify.com/platform/actors/development/actor-definition/dataset-schema)
45+
defaultMemoryMbytes:
46+
oneOf:
47+
- type: string
48+
example: get(input, 'startUrls.length', 1) * 1024
49+
- type: integer
50+
example: 1024
51+
description: Specifies the default amount of memory in megabytes to be used when the Actor is started. Can be an integer or a [dynamic memory expression](/platform/actors/development/actor-definition/dynamic-actor-memory).
4552
minMemoryMbytes:
4653
type: integer
4754
minimum: 256

sources/platform/actors/development/actor_definition/actor_json.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import TabItem from '@theme/TabItem';
2525
"name": "name-of-my-scraper",
2626
"version": "0.0",
2727
"buildTag": "latest",
28+
"defaultMemoryMbytes": "get(input, 'startUrls.length', 1) * 1024",
2829
"minMemoryMbytes": 256,
2930
"maxMemoryMbytes": 4096,
3031
"environmentVariables": {
@@ -66,7 +67,7 @@ Actor `name`, `version`, `buildTag`, and `environmentVariables` are currently on
6667

6768
| Property | Type | Description |
6869
| --- | --- | --- |
69-
| `actorSpecification` | Required | The version of the Actor specification. This property must be set to `1`, which is the only version available. |
70+
| `actorSpecification` | Required | The version of the Actor specification. This property must be set to `1`, which is the only version available. |
7071
| `name` | Required | The name of the Actor. |
7172
| `version` | Required | The version of the Actor, specified in the format `[Number].[Number]`, e.g., `0.1`, `0.3`, `1.0`, `1.3`, etc. |
7273
| `buildTag` | Optional | The tag name to be applied to a successful build of the Actor. If not specified, defaults to `latest`. Refer to the [builds](../builds_and_runs/builds.md) for more information. |
@@ -77,6 +78,7 @@ Actor `name`, `version`, `buildTag`, and `environmentVariables` are currently on
7778
| `input` | Optional | You can embed your [input schema](./input_schema/index.md) object directly in `actor.json` under the `input` field. You can also provide a path to a custom input schema. If not provided, the input schema at `.actor/INPUT_SCHEMA.json` or `INPUT_SCHEMA.json` is used, in this order of preference. |
7879
| `changelog` | Optional | The path to the CHANGELOG file displayed in the Information tab of the Actor in Apify Console next to Readme. If not provided, the CHANGELOG at `.actor/CHANGELOG.md` or `CHANGELOG.md` is used, in this order of preference. Your Actor doesn't need to have a CHANGELOG but it is a good practice to keep it updated for published Actors. |
7980
| `storages.dataset` | Optional | You can define the schema of the items in your dataset under the `storages.dataset` field. This can be either an embedded object or a path to a JSON schema file. [Read more](/platform/actors/development/actor-definition/dataset-schema) about Actor dataset schemas. |
81+
| `defaultMemoryMbytes` | Optional | Specifies the default amount of memory in megabytes to be used when the Actor is started. Can be an integer or a [dynamic memory expression string](./dynamic_actor_memory/index.md). |
8082
| `minMemoryMbytes` | Optional | Specifies the minimum amount of memory in megabytes required by the Actor to run. Requires an _integer_ value. If both `minMemoryMbytes` and `maxMemoryMbytes` are set, then `minMemoryMbytes` must be equal or lower than `maxMemoryMbytes`. Refer to the [Usage and resources](https://docs.apify.com/platform/actors/running/usage-and-resources#memory) for more details about memory allocation. |
8183
| `maxMemoryMbytes` | Optional | Specifies the maximum amount of memory in megabytes required by the Actor to run. It can be used to control the costs of run, especially when developing pay per result Actors. Requires an _integer_ value. Refer to the [Usage and resources](https://docs.apify.com/platform/actors/running/usage-and-resources#memory) for more details about memory allocation. |
8284
| `usesStandbyMode` | Optional | Boolean specifying whether the Actor will have [Standby mode](../programming_interface/actor_standby.md) enabled. |
Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
---
2+
title: Dynamic Actor memory
3+
description: Learn how to automatically adjust your Actor's memory based on input size and run options, so you can optimize performance and reduce costs without manual configuration.
4+
slug: /actors/development/actor-definition/dynamic-actor-memory
5+
---
6+
7+
import Tabs from '@theme/Tabs';
8+
import TabItem from '@theme/TabItem';
9+
10+
**Learn how to automatically adjust your Actor's memory based on input size and run options, so you can optimize performance and reduce costs without manual configuration.**
11+
12+
---
13+
14+
Dynamic Actor memory allows Actor to automatically adjust its memory allocation based on the input and run options. Instead of always using a fixed memory value, Actor can use just the right amount of memory for each run.
15+
16+
Optimal memory usually depends on the input size:
17+
18+
- A small input (for example, 10 URLs) might run fine on 512 MB.
19+
- A large input (for example, 1,000 URLs) could require 4 GB or more to run efficiently.
20+
21+
_Setting a single default value either wastes resources on small runs or slows down execution for large ones._ Dynamic memory solves this by calculating the required memory just before the run starts, based on the actual input and run options.
22+
23+
This helps:
24+
25+
- _Optimize performance_ for large inputs (more memory for bigger tasks).
26+
- _Reduce costs_ for small runs (less memory when it’s not needed).
27+
- _Provide better user experience_, so users get optimal performance without having to manually configure memory.
28+
29+
For example, the developer of an Actor could define an expression like:
30+
31+
```js
32+
min(get(input, 'startUrls.length', 1) * 64, 4096)
33+
```
34+
35+
This expression calculates memory based on the number of URLs provided by the user, making sure that for large inputs the Actor doesn’t exceed 4 GB.
36+
37+
:::info Dynamic memory is not runtime auto-scaling.
38+
39+
_This feature does not change memory while the Actor is running._
40+
41+
Memory is calculated once, right before the run begins. Each new run (for example, when the user provides different input) starts with memory calculated by the expression.
42+
43+
Users can still override it manually for each run.
44+
45+
:::
46+
47+
48+
## How is memory for a run determined?
49+
50+
The final memory assigned to an Actor run is determined in the following order:
51+
52+
1. _Run-level override (highest priority)._
53+
If the user explicitly sets memory when starting a run (via UI or API), this value is always used.
54+
55+
2. _Dynamic memory expression._
56+
If no run-level override is provided, the platform evaluates the dynamic memory expression defined in actor.json. The expression can use values from input and run options to calculate memory.
57+
58+
3. _Actor default memory._
59+
If no dynamic expression is defined, or if the expression fails to evaluate, the Actor falls back to its fixed default memory configured in the Actor’s UI settings.
60+
61+
4. _Platform limits._
62+
The final value is always rounded and clamped to platform-supported memory limits.
63+
64+
_In all cases, the memory value is finalized before the run starts and remains constant during execution._
65+
66+
## How to define dynamic memory expression
67+
68+
You can define a dynamic memory expression in your `actor.json`:
69+
70+
```json
71+
{
72+
"defaultMemoryMbytes": "get(input, 'startUrls.length' * 1024)"
73+
}
74+
```
75+
76+
Expressions are based on [MathJS](https://mathjs.org/), extended with custom helper function `get`.
77+
78+
79+
### Access run input and options
80+
81+
You can access variables in two ways:
82+
83+
1. Direct property access
84+
85+
```js
86+
input.foo + 512
87+
runOptions.maxItems + 256
88+
```
89+
90+
1. Double-brace syntax
91+
92+
```js
93+
{{input.foo}}
94+
{{runOptions.maxItems}}
95+
```
96+
97+
_You can mix both styles._
98+
99+
### Supported operations
100+
101+
- Arithmetic: `+`, `-`, `*`, `/`
102+
- Math functions: `min()`, `max()`, `ceil()`, `floor()`, `round()`, `log()`, `exp()`, `log10()`
103+
- Conditional logic:
104+
105+
```js
106+
condition ? valueIfTrue : valueIfFalse
107+
```
108+
109+
- Variable assignment:
110+
111+
```js
112+
memoryPerUrl = 64;
113+
get(input, 'startUrls') * memoryPerUrl
114+
```
115+
116+
### Safely access optional and/or nested values
117+
118+
Use `get()` to safely read nested properties or provide fallback values:
119+
120+
```js
121+
get(obj, 'path.to.property', defaultValue)
122+
```
123+
124+
Examples:
125+
126+
```js
127+
// Safely get array length
128+
get(input, 'startUrls.length', 1) // returns length or 1 if undefined
129+
130+
// Safely get nested property
131+
get(input, 'foo.bar.baz') // safely access nested objects
132+
133+
// Fallback
134+
get(input, 'foo', 1024) // returns 1024 if 'foo' doesn't exist
135+
136+
// Safely get an array element
137+
get(input, 'numbers.1') // element at index 1 of the numbers array
138+
```
139+
140+
### Memory limits
141+
142+
After the expression is evaluated, the memory value goes through these steps:
143+
144+
1. The result is rounded to the nearest power of two
145+
146+
- 300 -> 256 MB
147+
- 9001024 MB
148+
- 3,6004096 MB
149+
150+
1. If the Actor has minimum or maximum memory limits defined (`minMemoryMbytes` / `maxMemoryMbytes`), the value is adjusted to stay within those limits.
151+
1. The value is adjusted to stay within platform limits (128 MB to 32 GB).
152+
153+
:::info Fallback value
154+
If the calculation results in an error, the Actor will start with a fixed default memory, which can be configured in the Actor's UI settings.
155+
:::
156+
157+
### Example expressions
158+
159+
<Tabs groupId="example-expressions">
160+
<TabItem value="URL count" label="URL count">
161+
This expression calculates memory based on the number of URLs you want to process.
162+
It multiplies the number of URLs by 512 MB, so more URLs automatically get more memory.
163+
164+
```js
165+
get(input, 'startUrls.length', 1) * 512
166+
```
167+
168+
Explanation:
169+
170+
- `get(input, 'startUrls.length', 1)` → Safely reads length of `startUrls` array; defaults to 1 if not provided.
171+
- Allocates 512 MB per URL.
172+
173+
</TabItem>
174+
<TabItem value="Conditional logic" label="Conditional logic">
175+
176+
You can adjust memory based on a condition, for example user wants detailed scraping.
177+
178+
```js
179+
get(input, 'scrapeDetailed', false) ? 4096 : 1024
180+
```
181+
182+
Explanation:
183+
184+
- `get(input, 'scrapeDetailed', false)` → Reads a boolean flag from `input`; defaults to `false`.
185+
- `? 4096 : 1024` → If `scrapeDetailed` is `true`, allocate 4096 MB; otherwise, allocate 1024 MB.
186+
187+
</TabItem>
188+
<TabItem value="Variable assignment" label="Variable assignment">
189+
190+
For more complex cases, you can assign intermediate variables to simplify calculations.
191+
192+
```js
193+
urlsCount = get(input, 'startUrls.length', 0);
194+
reviewsMultiplier = max(get(input, 'maxReviews', 1) / 10, 1);
195+
urlsCount * reviewsMultiplier * 128
196+
```
197+
198+
Explanation:
199+
200+
- `urlsCount` → Number of URLs to process.
201+
- `reviewsMultiplier` → Adjusts memory based on the number of reviews; ensures at least 1.
202+
- `urlsCount * reviewsMultiplier * 128` → Final memory allocation, scaling with both URLs and review count.
203+
204+
</TabItem>
205+
<TabItem value="Double-brace variables" label="Double-brace variables">
206+
207+
You can also use double-brace syntax to refer to input variables.
208+
209+
```js
210+
{{input.itemsToProcess}} * 64
211+
```
212+
213+
Explanation:
214+
215+
- `{{input.itemsToProcess}}` → Reads the number of items to process.
216+
- Allocates 64 MB per item.
217+
</TabItem>
218+
219+
</Tabs>
220+
221+
### Testing expressions
222+
223+
#### Use npm package
224+
225+
You can use the [actor-memory-expressions](https://www.npmjs.com/package/@apify/actor-memory-expression) npm package not only to calculate memory for your expression, but also to write unit tests and verify the behavior of your expressions locally.
226+
227+
```bash
228+
npm install @apify/actor-memory-expression
229+
```
230+
231+
```js
232+
import { calculateRunDynamicMemory } from '@apify/actor-memory-expression';
233+
234+
await calculateRunDynamicMemory(
235+
"get(input, 'urls.length', 1) * 256",
236+
{
237+
input: { urls: ["a", "b", "c"] },
238+
runOptions: { maxTotalChargeUsd: 10 }
239+
}
240+
);
241+
```
242+
243+
#### Use CLI
244+
245+
You can use [Apify CLI](https://docs.apify.com/cli) to quickly evaluate expressions without writing code. It supports reading input from a JSON file and passing run options as flags.
246+
247+
```bash
248+
apify actor calculate-memory --input ./input.json --maxTotalChargeUsd=25
249+
```

sources/platform/actors/running/input_and_output.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,16 @@ As part of the input, you can also specify run options such as [Build](../develo
3434
![Run options](./images/input_and_output/actor-options.png)
3535

3636
| Option | Description |
37-
|:---|:---|
37+
| :--- | :--- |
3838
| Build | Tag or number of the build to run (e.g. **latest** or **1.2.34**). |
3939
| Timeout | Timeout for the Actor run in seconds. Zero value means there is no timeout. |
4040
| Memory | Amount of memory allocated for the Actor run, in megabytes. |
4141

42+
:::info Dynamic memory
43+
44+
If the Actor is configured by developer to use [dynamic memory](../development/actor_definition/dynamic_actor_memory/index.md), the system will calculate the optimal memory allocation based on your input. In this case, the **Memory** option acts as an override — if you set it, the calculated value will be ignored.
45+
46+
:::
4247

4348
## Output
4449

sources/platform/actors/running/usage_and_resources.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Check out the [Limits](../../limits.md) page for detailed information on Actor m
2121

2222
### Memory
2323

24-
When invoking an Actor, the caller must specify the memory allocation for the Actor run. The memory allocation must follow these requirements:
24+
When invoking an Actor, the caller can specify the memory allocation for the Actor run. If not specified, the Actor's default memory is used (which can be [dynamic](../development/actor_definition/dynamic_actor_memory/index.md)). The memory allocation must follow these requirements:
2525

2626
- It must be a power of 2.
2727
- The minimum allowed value is `128MB`

0 commit comments

Comments
 (0)