ArrayBuffer transfer S4
- Stage: Stage 4
- Status: Finished
- ECMAScript edition: ES2024
- Synchronized: Aug 28, 2026
- 中文译文 · Source repository
This proposal adds transfer, transferToFixedLength, and a detached getter to ArrayBuffer.prototype, enabling programmatic detachment and ownership transfer of ArrayBuffers. The API supports use cases like ownership semantics, realloc-like resizing, fixing resizable buffers to fixed length, and authoritative detachment checks.
The README below comes from the upstream repository and may contain outdated stage or status metadata. Use the proposal details above as the current source of truth.
ArrayBuffer.prototype.transfer and friends
Stage: 4 (included in ES2024). This repository is no longer active.
Author: Shu-yu Guo (@syg)
Champion: Shu-yu Guo (@syg), Jordan Harband (@ljharb), Yagiz Nizipli (@anonrig)
Introduction
ArrayBuffers may be transferred and detached by HTML's serialization algorithms, but there lacks a programmatic JS API for the same expressivity. A programmatic API is useful for programming patterns such as transferring ownership of ArrayBuffers, optimized reallocations (i.e. realloc semantics), and fixing resizable ArrayBuffers into fixed-length ones. This proposal fills out this expressivity by adding new methods to ArrayBuffer.prototype.
This proposal is spun out of the resizable buffers proposal. At the time of spinning out, resizable buffers was Stage 3, and this proposal was demoted to Stage 2.
API
Motivation and use cases
Ownership
A "move and detach original ArrayBuffer" method can be used to implement ownership semantics when working with ArrayBuffers. This is useful in many situations, such as disallowing other users from modifying a buffer when writing into it.
For example, consider the following example from @domenic from the original transfer proposal:
Depending on the time taken for await validate(arrayBuffer), the validation result may be stale due to the callback passed to setTimeout. A defensive approach would copy the input first, but this is markedly less performant:
With transfer, the ownership transfer can be succinctly expressed:
Realloc
The same transfer API, when passing a newByteLength argument, can double to have the same expressivity as realloc. Operating systems often implement realloc more efficiently than a copy.
Fixing resizable buffers to be fixed-length
The transferToFixedLength method is a variant of transfer that always returns a fixed-length ArrayBuffer. This is useful in cases when the new buffer no longers needs resizability, allowing implementations to free up virtual memory if resizable buffers were implemented in-place (i.e. address space is reserved up front).
Checking detachedness
Owing to the messy history of TypedArray and ArrayBuffer standardization, and preservation of web compatibility, TypedArray views on detached buffers throw for some operations (e.g. prototype methods), and return sentinel values (0 or undefined) for others (e.g. indexed access and length).
The detached getter is added to authoritatively determine whether an ArrayBuffer is detached.
Currently, there isn't any performant way of detecting whether an ArrayBuffer is detached. The following implementation is an example of how the detachedness can be detected, but has some flaws in V8: functions with try catch blocks are not inlined in V8. See also this Node internal comment.
FAQ and design rationale tradeoffs
Why do both transfer and transferToFixedLength exist instead of a single, more flexible method?
Most folks seem to have the intuition that the move semantics, being the primary use case, ought to preserve resizability. Transferring ArrayBuffers in HTML serialization preserves resizability, and symmetry with that is good for intuition.
A flexible transfer also complicates the API design for a more minority use case, thus the separate transferToFixedLength method.
Why can't I pass a new maxByteLength to transfer?
One of the goals of transfer, in addition to detach semantics, is to be more efficiently implementable than a copy in user code. It is not clear to the author that for resizable buffers implemented in-place, reallocation of the virtual memory pages is possible and efficient on all popular operating systems.
And besides it adds complexity in service of a more minority use case. Resizable buffers ought to be allocated with sufficient maximum size from the start.
If performance is the goal, why add new methods instead of implementing copy-on-write (CoW) as a transparent optimization?
In a word, security.
ArrayBuffers are a very popular attack vector for exploiting JavaScript engines. An important security mitigation engines employ is to ensure the ArrayBuffer's data pointer is constant and does not move. For this same reason, resizable buffers are specified to allow in-place implementation.
CoW ArrayBuffers may be implemented by moving the data pointer. When the CoW ArrayBuffer is modified, new memory is allocated and the backing store is updated. However, this conflicts with the security mitigation.
It is possible to both implement copy-on-write ArrayBuffers and keep the "fixed data pointer" security mitigation only with additional help from the underlying operating system: by mapping new virtual memory that is marked as CoW and initially point to the same physical pages as the source buffer. This technique is, however, not portable.
At this time, Google Chrome deems this mitigation important enough for security to not implement CoW ArrayBuffers.
How is get detached() used in browsers and in runtimes?
- Node.js discussed adding a public API for
get detached() - WebKit has
isDetachedin internalArrayBufferclass - V8 added
v8::ArrayBuffer::WasDetachedwhich was later backported to Node.js and used in Node webstreams.
How is transfer used in browsers and in runtimes?
Most browsers use detach() as the name for detaching ArrayBuffers.
- V8 has
Detach()asv8::ArrayBuffer::Detach() - WebKit has
void detach() - Node.js has an internal implementation to support detaching internal buffers called
transferArrayBuffer, and used in Node webstream.
Open questions
Do we really need transferToFixedLength?
Feels nice to round out the expressivity, but granted the use case here isn't as compelling as transfer.
History and acknowledgment
Thanks to: