createImageSizes decodes the source once per image size, all at once, so one upload can take hundreds of MB
Maintainers usually reply within 1 day
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 76/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- node.js, typescript
- Domain
- backend, performance
Research direction
Read packages/payload/src/uploads/image-resizing/createImageSizes.ts and trace how imageSizes are processed, especially the concurrent Promise.all and the omit branch. Compare peak memory when sizes are built sequentially rather than concurrently. Done means uploads produce the configured sizes and the measured peak memory is reduced; verify with the reported 7000x7000 PNG reproduction.
Written by the indexing model from the issue text.
Description
Describe the Bug
createImageSizes builds every configured image size at once (Promise.all over imageSizes). Each size pipeline decodes the whole source image, so one upload holds one full decoded copy per size at the same time. Peak memory is roughly sizes x width x height x channels.
A small file can therefore take hundreds of MB. A flat 7000x7000 PNG of ~320 KB with four imageSizes grows the process by ~600 MB. In a memory-limited container that is enough for the kernel to kill the process, and since the client retries, each retry takes down the next replica.
Measured on 3.90.1 (sharp 0.34.3), one payload.create on a collection with WebP imageSizes, peak RSS growth:
| imageSizes | growth |
|---|---|
| 0 | 4 MB |
| 1 | 138 MB |
| 4 | 591 MB |
| 4, sizes built one after another | 162 MB |
The code is unchanged in 3.90.2: packages/payload/src/uploads/image-resizing/createImageSizes.ts.
Link to the code that reproduces this issue
Not a public repo. Minimal config below.
Reproduction Steps
- Collection with
upload.imageSizesof four WebP sizes, for example widths 1600, 1240, 960 and 690, withwithoutEnlargement: true. - Pass
sharpin the config. - Upload a 7000x7000 PNG with a flat background (a few hundred KB).
- Watch process RSS during the create: it grows by about four decoded copies of the image.
Building the sizes in sequence (for ... of in place of Promise.all(imageSizes.map(...)), with continue for the omit branch) brings the peak down to about one decoded copy.
Which area(s) are affected?
area: core, Uploads
Environment Info
payload: 3.90.1
sharp: 0.34.3
node: 24
- Dominant language
- TypeScript
- Stars
- 45.5k
- Forks
- 4.3k
- Avg merge
- 1d 19h
- Merged PRs (30d)
- 309
Getting set up
Starts the project's dev container in your browser, under your own GitHub account.
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from payloadcms/payload
-
Grid view: show the file placeholder when a thumbnail image fails to loadPossibly taken @lazerg claimed this 1 day ago. OpenBug
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
payloadcms/payload#19181 ·
Maintainers usually reply within 1 day
-
WhereBuilder throws "Cannot read properties of undefined (reading 'value')" when the list URL filters on a field that is not filterablePossibly taken A pull request linked to this issue is open or already merged. OpenBug
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
payloadcms/payload#19002 · 1 comment ·
Maintainers usually reply within 1 day
-
Regression: `findByID` with `disableErrors: true` throws `NotFound` for null/empty ids since 3.91.0Possibly taken @Krrishkumar125 claimed this 8 days ago. Openarea: core Bug invalid-reproduction status: needs-triage v3
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
payloadcms/payload#18935 · 2 comments ·
Maintainers usually reply within 1 day
-
bug: Local API call with req resets req.fallbackLocale to defaultLocalePossibly taken A pull request linked to this issue is open or already merged. Openarea: core Bug created-by: Contributor
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
payloadcms/payload#18768 ·
Maintainers usually reply within 1 day
-
[plugin-multi-tenant] Infinite redirect loop with custom tenantFieldName and isGlobal collectionsPossibly taken A pull request linked to this issue is open or already merged. OpenBug plugin: multi-tenant status: needs-triage v3
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
payloadcms/payload#18690 ·
Maintainers usually reply within 1 day
All issues in payloadcms/payload
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
CopilotKit/openmuse#215 ·
Maintainers usually reply within 3 days
-
b:minor bug
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
software-mansion/argent#1698 ·
Maintainers usually reply within 1 day
-
e2e-failure ready-to-code
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
redhat-developer/rhdh-plugin-export-overlays#4624 · 1 comment ·
Maintainers usually reply within 1 day