Skip to content

Conversation

@danpoletaev
Copy link
Contributor

@danpoletaev danpoletaev commented Dec 15, 2025

This PR adds documentation for the recently released Dynamic Actor Memory feature. I also added backlinks from related documentation sections.

More information in spec


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.

Written by Cursor Bugbot for commit 0305a25. Configure here.

@danpoletaev danpoletaev self-assigned this Dec 15, 2025
@danpoletaev danpoletaev added the adhoc Ad-hoc unplanned task added during the sprint. label Dec 15, 2025
@apify-service-account
Copy link

Preview for this PR was built for commit 0305a25 and is ready at https://pr-2145.preview.docs.apify.com!

@apify-service-account
Copy link

Preview for this PR was built for commit 6f1618d and is ready at https://pr-2145.preview.docs.apify.com!

@apify-service-account
Copy link

Preview for this PR was built for commit 90f48e9 and is ready at https://pr-2145.preview.docs.apify.com!

@apify-service-account
Copy link

Preview for this PR was built for commit e203dce and is ready at https://pr-2145.preview.docs.apify.com!

@apify-service-account
Copy link

Preview for this PR was built for commit b3e4628 and is ready at https://pr-2145.preview.docs.apify.com!

@github-actions github-actions bot added the t-core-services Issues with this label are in the ownership of the core services team. label Dec 18, 2025
@apify-service-account
Copy link

Preview for this PR was built for commit 133af16c and is ready at https://pr-2145.preview.docs.apify.com!

@apify-service-account
Copy link

Preview for this PR was built for commit 52099e77 and is ready at https://pr-2145.preview.docs.apify.com!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This component is only used in the Build component, which is only returned from "get build", "build actor" and "abort actor build" endpoints - its that correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, correct

Copy link
Contributor

@tobice tobice left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, forgot to submit my review 🤦

:::

---

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(opt) I'm kind of missing here a section How dynamic memory works.

First of all, we should double-down on the fact that dynamic does not mean that the Actor can on-the-fly ask for more memory. IMHO this is easily confused (we have seen it even internally).

Second, it should explain the whole "memory configuration pipeline", as in, how is memory for a run determined (memory expression vs Actor defaults vs run overrides).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, refactored it 👍


Dynamic Actor memory allows Actors 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.

This helps:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(nit) This is kind of overlapping with Why dynamic memory matters.


---

### Writing Expressions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(nit) I don't think you need this headline, it can be merged with the previous section.

}
```

- The expression is evaluated _before the run starts_.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(nit) This is not really related how to define the expression, but rather how it works. See my suggestion above.


### Example expressions

1. Simple memory based on URL count
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
1. Simple memory based on URL count
1. Memory based on URL count

The "simple" sounds weird.

```js
get(input, 'startUrls.length', 1) * 512
```
1. Conditional logic
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
1. Conditional logic
1. Increase memory if the user wants to scrape additional details

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(nit) Maybe instead of a generic headline that doesn't say much explain what the expression actually does?

I kind of struggle with interpreting the expressions and I'll hardly be the only one 😄 This can help.

Dtt below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored this

1. More complex calculation

```js
urls = get(input, 'startUrls.length', 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
urls = get(input, 'startUrls.length', 0);
urlCount = get(input, 'startUrls.length', 0);


---

### Key Takeaways
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(opt) Is this needed? Is such a section something that we usually do?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not really, and even if we would do it it shouldn't have been in Title case rather in Sentence case

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed key takeaways

| Memory | Amount of memory allocated for the Actor run, in megabytes. |

:::info Dynamic memory
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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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.
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.

Comment on lines 119 to 129
### Memory limits and clamping

After evaluation:

1. The result is rounded up to the nearest power of two

- 900 → 1024 MB
- 3,600 → 4096 MB

2. It is clamped to actor-defined min/max (`minMemoryMbytes` / `maxMemoryMbytes`).
3. It is clamped to platform limits (128 MB to 32 GB).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One more thing. Why use the word "clamp" here? Is there a specific reason? Otherwise, I'd just go with limits, not clamping:

Suggested change
### Memory limits and clamping
After evaluation:
1. The result is rounded up to the nearest power of two
- 900 → 1024 MB
- 3,600 → 4096 MB
2. It is clamped to actor-defined min/max (`minMemoryMbytes` / `maxMemoryMbytes`).
3. It is clamped to platform limits (128 MB to 32 GB).
### Memory limits
After the expression is evaluated, the memory value goes through these steps:
1. The result is rounded up to the nearest power of two
- 900 → 1024 MB
- 3,600 → 4096 MB
2. If the Actor has minimum or maximum memory limits defined (`minMemoryMbytes` / `maxMemoryMbytes`), the value is adjusted to stay within those limits.
3. The value is adjusted to stay within platform limits (128 MB to 32 GB).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also we should be using only 1. to create ordered lists. It makes maintenance much easier

Copy link
Contributor

@janbuchar janbuchar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The OpenAPI part looks good to me

Copy link
Contributor

@TC-MO TC-MO left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left few comments as well

Comment on lines 135 to 161
### Example expressions

#### Simple memory based on URL count

```js
get(input, 'startUrls.length', 1) * 512
```

#### Conditional logic

```js
get(input, 'scrapeDetailed', false) ? 4096 : 1024
```

#### More complex calculation

```js
urls = get(input, 'startUrls.length', 0);
reviewsMultiplier = max(get(input, 'maxReviews', 1) / 10, 1);
urls * reviewsMultiplier * 128
```

#### Using double-brace variables

```js
{{input.itemsToProcess}} * 64
```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can use Tabs component here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, refactored it


---

### Key Takeaways
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not really, and even if we would do it it shouldn't have been in Title case rather in Sentence case

apify actor calculate-memory --input ./input.json --maxTotalChargeUsd=25
```

---
Copy link
Contributor

@TC-MO TC-MO Dec 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason why there are these lines to break the page? we do it once to at the beginning usually to provide TL:DR of what the page is about but do not use it later for page break

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed


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.

```shell
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is not correct language declaration for code block. IIRC it's based on Prism.js and in such cases bash is generally used (this is valid for whole document)

Comment on lines 119 to 129
### Memory limits and clamping

After evaluation:

1. The result is rounded up to the nearest power of two

- 900 → 1024 MB
- 3,600 → 4096 MB

2. It is clamped to actor-defined min/max (`minMemoryMbytes` / `maxMemoryMbytes`).
3. It is clamped to platform limits (128 MB to 32 GB).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also we should be using only 1. to create ordered lists. It makes maintenance much easier

@apify-service-account
Copy link

Preview for this PR was built for commit 7ab0ccc9 and is ready at https://pr-2145.preview.docs.apify.com!

@apify-service-account
Copy link

Preview for this PR was built for commit 50b78baa and is ready at https://pr-2145.preview.docs.apify.com!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

adhoc Ad-hoc unplanned task added during the sprint. t-core-services Issues with this label are in the ownership of the core services team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants