Concepts

ArrayBuffers represents a byte-array in physical memory. An ArrayBuffer is the actual storage for the bytes but is rarely used directly - in fact, you don't have access to read content of ArrayBuffer directly and can only pass a reference for it. They are on the other hand used for binary data transfers between server and client, or from the user's file system via Blobs.


ArrayBuffer byte array in memory - each index equals one byte. ArrayBuffer is aligned in memory.

To read the content of an ArrayBuffer you need to use a view. This sits on top and offers an "api" to access the bytes by different width types, or arbitrarily.

Width-dependent Views

The different views are used depending on what you need. If you only need to read byte values, ie. signed values between -128 and 127 -or- unsigned values between 0-255, you would use Int8Array or Uint8Array. Notice that their names are a bit "misleading" as they are views and not arrays, and only references the underlying ArrayBuffer.

Likewise, you have views for Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array and Float64Array.

With the exception of *int8Arrays the others come with some requirement to ArrayBuffer size. For example, a Uint32Array view must sit on top of an ArrayBuffer that is divisible by four, otherwise it throws an error. *int 16 views would require a two-byte boundary.

This is usually not a problem because you can specify number of indexes using the view's constructor directly and a matching ArrayBuffer will be created automatically for it fulfilling these requirements.

And since the ArrayBuffer is a byte-array a *int16 view reads two bytes from it - or, one index = two bytes, *int32 four, or one index = four bytes, and so on.

The main difference between Uint8Array and Uint8ClampedArray is that values outside the range are subject to modulo (for example 256 becomes 0) with the ordinary arrays. In the clamped array the values are as suggested clamped instead (256 becomes 255).


Int16/Uint16 views - each index represents two bytes and is memory aligned.


Int32/Uint32 and Float32 views - each index represents four bytes and is memory aligned.


Float64 view - each index represents eight bytes and is memory aligned.

DataView for flexibility

Then there is the DataView. This is intended for scenarios where you need a flexible ArrayBuffer and need to read variable widths and from positions in the buffer that is not necessarily width or memory aligned.

For example, a *int32 index will always point to a memory location that is dividable by four. A DataView on the other hand can read a Uint32 from say, position 5 and will take care of all the needed steps internally (bit shifting, masking etc.), but at the cost of a tiny overhead.

One other difference is that a DataView doesn't use indexes but absolute byte-positions for the data it represents, and it comes with its own methods to read or write various widths from/to any position.


DataView - can read from any position and any width.

In other cases you can use several different views referencing the same underlying ArrayBuffer.

There is currently not 64-bits views for integer numbers, but seem to be proposed for ES8.

SharedArrayBuffers

It's also useful to mention the new SharedArrayBuffers that can be used across web workers.

You could (and still can) use transferable objects in the past in some browsers, but SharedArrayBuffers is more efficient in the sense the memory stays the same, only information about it is transferred. SharedArrayBuffers cannot become detached as ArrayBuffers can.

Purpose and Usage areas

Typed arrays are good to store specific numeric values and are fast. Bitmaps is a typical candidate for typed arrays (e.g. canvas 2D/WebGL).

Heavy data processing of data inside web workers is another use and so on. I already mentioned binary transfer between client and server or the file-system.

DataViews are perfect to parse or build binary files and file formats.

Typed arrays are an excellent way to pack binary data for sending over the net, to server or via web sockets and things like data-channels for WebRTC.

If you deal with audio, video, canvas, or media recording, there is often no way around using typed arrays.

The keys for using typed arrays are performance and memory. They are most often used in special scenarios, but there is nothing wrong using them in ordinary cases when you only need to store numeric values (or utf-8 strings, encryption vectors etc.). They are fast and have a low memory footprint.

Precautions

There are a couple of precautions to be aware of:

Byte-order

Some precautions must be made in regards to byte-order. Typed arrays always reflects the CPU-architecture they run under, ie. little-endian or big-endian. Most consumer systems are little-endian but when using *int16 and *int32 arrays you must pay special attention to byte-order. DataView can help with this part too, but is not always a good choice if performance is important.

Byte-order is also important when receiving data from server. They are usually always in big-endian format (AKA "network order"). For parsing file formats the same will apply.

Floating Point Number Encoding

Float32/Float64 will read and write numbers encoded in the IEEE-754 format. This is also something to be aware of if several views are used for the same buffer.

Cross-browser Support

Most browsers supports typed arrays nowadays. If you have to deal with older browsers you have to go back to IE9 or older mobile browsers to not be able to use them.

Safari is not particular optimized in regards to their performance, but the other benefits are there. Version 5.1 does not support Float64.

Mobile devices has their own hardware limitations, but in general: typed arrays are safe to use. For special cases there exist a polyfill.

Answer from user1693593 on Stack Overflow
🌐
Reddit
reddit.com › r/node › eli5: file, uint8array, buffer, arraybuffer, bytesarray, blob…
r/node on Reddit: ELI5: File, Uint8Array, Buffer, Arraybuffer, BytesArray, Blob…
December 16, 2021 -

I’m always ending up guessing.. I need to somehow understand. I have no idea what I’m doing when working with files. Just trying stuff until it works. Someone plz ELI5..

My current issue is getting a png file from Firebase storage which gives a “file” which I’m trying to add on a pdf, where the library expects a Uint8Array or Arraybuffer. I’ve been doing similar things before. But end up just guessing my way until it works, and this time.. well it doesn’t work. I guessed it all with no success. I don’t know what I’m doing so I guess I need to actually learn ;)

Top answer
1 of 2
36
A digital system, like a computer works on digital data, thus things which can be represented as digits. Or simpler: Computer sees a bit of numbers and works on them. Also a text is just a long number. Some time ago, one decided to have computers work on binary digits and to group 8 out of those as the typical size. That is a byte. (There were computers using other byte sizes, that's why sometimes, especially in network protocols, it is called octet) With a byte of eight bits you can represent 256 values. (From 0 to 255) over multiple decades there were discussions on representing text (actually that was prr-computer already with telegraphs etc) and one found the ASCII rules to map between numeric values and characters. Each letter in the English alphabet got a code. Thus the word Hello becomes the sequence of numbers 72 101 108 108 111 Now decimal system ia nice when counting with fingers, but not so good for a binary machine. As said we have the byte, thus instead ten digits is inconvenient so we use a number system with base 16, thus any digit can not only have ten different values (0 to 9) but 16 (0 to 9 and A to F) Thus the same numbers as above can be written in hex 0x48 0x65 0x6C 0x6C 0x6F Now each byte is represented by two hex digits which gives a nice structure (and if you notice that 0x41 is A and 0x61 is a you start to understand ASCII) Now over time 256 characters wasn't enough for represting text in all languages, so after many years and messing around with different code pages and encodings smart folks came up with Unicode and Utf-8 to encode all characters. Won't go there too deep, but in essence utf-8 uses the ASCII table for the first 128 characters (half a byte, the lower half) and all other characters use multiple bytes. The German letter Ä fornisntance is 0xC3 0x48. In addition the Unicode standard has specific rules on sorting and comparing those values and some fancy transformations. (Sorting rules are even language dependent, so the German Ä can be sorted like AE, behind Z or simply as A) Wenn Browsers and JavaScript were created it was decided that a string in JavaScirpt shall be Unicode data. This is logical as websites are full of human readable text and properties of Unicode are good (well, the story is more complicated there, but good enough) This was good for the time where Web was working with simple websites and JavaScript was doing minor text manipulation. However for lower layers of the compitong stack data is just a sequence of bytes. In memory you have bytes. A file is a sequence of bytes. The meaning of those bytes might be Unicode text, might be an image, might even be bianry program code all are just bytes. The difference is only in the one looking at it. Now treating all data as unicode string will do harm, as they have all the assumptions on top where only specific byte sequences are valid and so on. So something else had to be added. And in fact different groups added different things. Before we can explain that, one step more is needed: as said interpretation depends on who looks at the data. So back to our numbers and from decimal and hex to binary. As said 8 bit are a byte. The number 1 in binary with it 8 bits would look like 0b00000001 Here using 0b as prefix, so you interpret it as binary, not hey, not decimal. The value 127 inn inary looks like this: 0b01111111 all bits, but the first set. Now something fancy happens when we set the first bit to 1 as well: 0b11111111 This can either be 255 or -1. Wait what negative!? You will ask: Yes, there eisna problem with these numbers: Our byte has to represent negative numbers as well. And then the first digit tells us whether it's negative or positive. And whenever we look at the byte we have to make a choice how we look at it. Is it a text character? Is it a positive number? A negative number? The byte doesn't know and doesn't care only we when looking at it. Now the Uint8Array enters! By giving a sequence of bytes (some area in memory) to an Uint8Buffer we tell it "look at those bytes and treat tit like a sequence of bytes, where each byte is a 8 bit unsigned number" and by that we can work with those.bytes and each byte will be a number 0 to 256 and whatever we do with the array decides on what it does with those bytes. Maybe it is a pixel in an image, maybe an frequency on an audio file, maybe ... Now another term there eisnthe Buffer. A buffer is just some area in memory. An arrayBuffer is "this is my area of memory, but I haven't yet decided how i will interpret it" I said Buffer, I said complicazednhsorory ... That tis that Node.js developers Hand this issue before ArrayBuffer d Uint8Array was defined, so they created their own thing, which is similar to an Unit8Array (modern versions of Buffer are built on Uint8Array) but don't be confused, buffer is a generic term for some data stored somewhere, which is distinct from Buffer, which is a type in Node.js. Now there ris a bit more. 256 is a bit low formmany purposes. So you can group multiple bytes and make them digits in a larger number. Quite typical are efor 4 byte, which are 32 bit. Thus a Int32Array takes 4 bytes at once from the underlying data (the ArrayBuffer, the buffer, the memory region) and makes it a 32 bit signed number (- 2147483648 to 2147483647) the Uint32Array (0 to 4294967295) and if that isn't enought there are big(u)int64Array, which look at 8 byte at a time, which is also the number of byte/bit a modern CPU can store in it's register, transfer though bus and process the best, hence 64bit architecture. The key thing is: memory (RAM, disk or any other form) in modern computers is just a sequence of bytes and the way you look at it decides on the meaning. The computer doesn't know and you have to tell it. Uint8Array is the typically representation for low level work. ArrayBuffer is when you haven't decided, yet and all else are more special.
2 of 2
1
it's a bit of a Pia esp when different libs want diff types. An ArrayBuffer is raw data. Like a big bag of data. You can't do anything with it - but if you convert it to something that can look inside the bag (Uint8Array), you can read / write it. If you just want to read, then Blob is your guy.
Top answer
1 of 2
154

Concepts

ArrayBuffers represents a byte-array in physical memory. An ArrayBuffer is the actual storage for the bytes but is rarely used directly - in fact, you don't have access to read content of ArrayBuffer directly and can only pass a reference for it. They are on the other hand used for binary data transfers between server and client, or from the user's file system via Blobs.


ArrayBuffer byte array in memory - each index equals one byte. ArrayBuffer is aligned in memory.

To read the content of an ArrayBuffer you need to use a view. This sits on top and offers an "api" to access the bytes by different width types, or arbitrarily.

Width-dependent Views

The different views are used depending on what you need. If you only need to read byte values, ie. signed values between -128 and 127 -or- unsigned values between 0-255, you would use Int8Array or Uint8Array. Notice that their names are a bit "misleading" as they are views and not arrays, and only references the underlying ArrayBuffer.

Likewise, you have views for Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array and Float64Array.

With the exception of *int8Arrays the others come with some requirement to ArrayBuffer size. For example, a Uint32Array view must sit on top of an ArrayBuffer that is divisible by four, otherwise it throws an error. *int 16 views would require a two-byte boundary.

This is usually not a problem because you can specify number of indexes using the view's constructor directly and a matching ArrayBuffer will be created automatically for it fulfilling these requirements.

And since the ArrayBuffer is a byte-array a *int16 view reads two bytes from it - or, one index = two bytes, *int32 four, or one index = four bytes, and so on.

The main difference between Uint8Array and Uint8ClampedArray is that values outside the range are subject to modulo (for example 256 becomes 0) with the ordinary arrays. In the clamped array the values are as suggested clamped instead (256 becomes 255).


Int16/Uint16 views - each index represents two bytes and is memory aligned.


Int32/Uint32 and Float32 views - each index represents four bytes and is memory aligned.


Float64 view - each index represents eight bytes and is memory aligned.

DataView for flexibility

Then there is the DataView. This is intended for scenarios where you need a flexible ArrayBuffer and need to read variable widths and from positions in the buffer that is not necessarily width or memory aligned.

For example, a *int32 index will always point to a memory location that is dividable by four. A DataView on the other hand can read a Uint32 from say, position 5 and will take care of all the needed steps internally (bit shifting, masking etc.), but at the cost of a tiny overhead.

One other difference is that a DataView doesn't use indexes but absolute byte-positions for the data it represents, and it comes with its own methods to read or write various widths from/to any position.


DataView - can read from any position and any width.

In other cases you can use several different views referencing the same underlying ArrayBuffer.

There is currently not 64-bits views for integer numbers, but seem to be proposed for ES8.

SharedArrayBuffers

It's also useful to mention the new SharedArrayBuffers that can be used across web workers.

You could (and still can) use transferable objects in the past in some browsers, but SharedArrayBuffers is more efficient in the sense the memory stays the same, only information about it is transferred. SharedArrayBuffers cannot become detached as ArrayBuffers can.

Purpose and Usage areas

Typed arrays are good to store specific numeric values and are fast. Bitmaps is a typical candidate for typed arrays (e.g. canvas 2D/WebGL).

Heavy data processing of data inside web workers is another use and so on. I already mentioned binary transfer between client and server or the file-system.

DataViews are perfect to parse or build binary files and file formats.

Typed arrays are an excellent way to pack binary data for sending over the net, to server or via web sockets and things like data-channels for WebRTC.

If you deal with audio, video, canvas, or media recording, there is often no way around using typed arrays.

The keys for using typed arrays are performance and memory. They are most often used in special scenarios, but there is nothing wrong using them in ordinary cases when you only need to store numeric values (or utf-8 strings, encryption vectors etc.). They are fast and have a low memory footprint.

Precautions

There are a couple of precautions to be aware of:

Byte-order

Some precautions must be made in regards to byte-order. Typed arrays always reflects the CPU-architecture they run under, ie. little-endian or big-endian. Most consumer systems are little-endian but when using *int16 and *int32 arrays you must pay special attention to byte-order. DataView can help with this part too, but is not always a good choice if performance is important.

Byte-order is also important when receiving data from server. They are usually always in big-endian format (AKA "network order"). For parsing file formats the same will apply.

Floating Point Number Encoding

Float32/Float64 will read and write numbers encoded in the IEEE-754 format. This is also something to be aware of if several views are used for the same buffer.

Cross-browser Support

Most browsers supports typed arrays nowadays. If you have to deal with older browsers you have to go back to IE9 or older mobile browsers to not be able to use them.

Safari is not particular optimized in regards to their performance, but the other benefits are there. Version 5.1 does not support Float64.

Mobile devices has their own hardware limitations, but in general: typed arrays are safe to use. For special cases there exist a polyfill.

2 of 2
5

I prefer to use TypedArray in function parameters and return type. A TypedArray could represent a part view of an ArrayBuffer, which means it might not be the same size of the underlying buffer. For example:

const buff = new ArrayBuffer(12);

// it will have the bytes from offset 4 to 7 (included)
const arr = new Uint8Array(buff, 4, 4);

The part view of the data is your function's concern, not the whole underlying buffer.

And what if you choose passing ArrayBuffer into the function in this case? Then you have to create a new ArrayBuffer, which is complex and performance harmful:

const buff = new ArrayBuffer(12);
foo(new Uint8Array(buff).slice(4, 8).buffer)

function foo(buff: ArrayBuffer) {
}

But, if you use TypedArray, be careful when you wanna write bytes into storage (like indexedDB). Be sure the TypedArray is align with the underlying buffer, otherwise you might write the whole data into the storage.


You could also choose to accept both ArrayBuffer and TypedArray if you like:

function foo(data: ArrayBufferView | ArrayBuffer) {
  // Convert to a view, or any TypedArray you want
  if(!ArrayBuffer.isView(data)) data = new Uint8Array(data); 
  // ...
}
Discussions

What is the difference between an array and an ArrayBuffer?
I'm just wondering why everyone uses ArrayBuffer instead of just a normal array, string or stringified JSON for sending messages from the server to the client. Is it more efficient? Also, just wondering what Uint8Array is, how it is different, where to use the two etc. More on stackoverflow.com
🌐 stackoverflow.com
You shouldn't be allowed to pass Uint8Array when ArrayBuffer is expected ...
What doesn't make sense ? A Uint8Array extends an ArrayBuffer so... ? Every Uint8Array is an ArrayBuffer. More on reddit.com
🌐 r/typescript
25
0
December 14, 2024
Node.js - Buffer vs Uint8Array
With TypedArray now available, the Buffer class implements the Uint8Array API in a manner that is more optimized and suitable for Node.js. More on stackoverflow.com
🌐 stackoverflow.com
Type usages of Uint8Array as Uint8Array<ArrayBuffer>
Describe the bug With the most recent version of TypeScript, there was a change to make the type of Uint8Array such that the buffer can be either ArrayBuffer or SharedArrayBuffer. While controversi... More on github.com
🌐 github.com
4
December 7, 2025
🌐
Medium
medium.com › @julienetienne › different-types-of-arrays-in-javascript-and-when-to-use-them-77f7843b71de
Different Types of Arrays in JavaScript + When to Use Them | by Julien Etienne | Medium
February 8, 2024 - // We allocate a buffer of only 4 bytes (32 bits) const buffer = new ArrayBuffer(4) // Make an 8 bit unsigned integer TypedArray view const uint8 = new Uint8Array(buffer) // Assign 123 uint8[0] = 123 // Assign 456 uint8[1] = 456 // Log the items for (const item of uint8) console.log(item) // 123 // 200 // 0 // 0 // WTF is going on?
🌐
Medium
medium.com › weekly-webtips › javascript-lost-in-binaries-buffer-blob-uint8array-arraybuffer-ed8d2b4de44a
JavaScript: Lost in binaries — Buffer/Blob/UInt8Array/ArrayBuffer | by Naveen Kumarasinghe | Medium
April 2, 2023 - ArrayBuffer provides a fixed-size block of memory that can be manipulated with binary data, while Uint8Array provides a view into that memory for more efficient manipulation. Blob is used to represent binary data that is used in HTTP requests ...
🌐
Azurewebsites
benchmarklab.azurewebsites.net › Benchmarks › Show › 7537 › 0 › copy-arraybuffer-dataview-vs-uint8arrayset-vs-float64ar
Benchmark: copy ArrayBuffer: DataView vs Uint8Array.set vs Float64Array.set vs by bytes - MeasureThat.net
DataView vs Uint8Array by bytes vs Native Array · copy ArrayBuffer: DataView vs Uint8Array.set vs Float64Array.set vs by bytes v2 · copy ArrayBuffer: DataView vs Uint8Array.set vs Float64Array.set vs by bytes (2) Comments · Do you really want to delete benchmark?
🌐
Pavel Romanov
pavel-romanov.com › uint8array-vs-dataview-choosing-the-right-buffer-view-in-javascript
Uint8Array vs DataView: Best Buffer Choice - Pavel Romanov
August 20, 2024 - For example, using Uint8Array means that we only work with data range between 0 and 255. Typed arrays are quite convenient when we work only with a single type of data per buffer.
🌐
JavaScript.info
javascript.info › tutorial › binary data, files
ArrayBuffer, binary arrays
July 11, 2022 - It’s the “eyeglasses” that give an interpretation of the bytes stored in the ArrayBuffer. ... Uint8Array – treats each byte in ArrayBuffer as a separate number, with possible values from 0 to 255 (a byte is 8-bit, so it can hold only ...
Find elsewhere
Top answer
1 of 1
41

An ArrayBuffer is more than just a simple array. It contains raw binary data. This is very useful for direct memory manipulation and conserving space.

When you create a normal array, you won't get a proper set of contiguous memory in many cases since arrays can contain any combination of different kinds of objects. This is useful when you have dynamic data and multiple types together (frequently happens in JS) but is not so useful when you know the exact layout of memory that you need.

This also allows you to view the data at the byte level. For example, it's pretty common in binary data formats to have a n byte long identifier number, an m byte long field telling you how many bytes are used for this field, and m' bytes of data that actually makes up the data field.

[ identifier ][ bytes of data ][ data ]

With an ArrayBuffer, you have the option of moving through that data on the byte level by using various Views. A regular array doesn't allow you to move through the data with that level of granularity because no guarantees are made about the memory layout.

Finally, because you are telling the compiler/interpreter exactly how much space you're going to use and exactly how you're going to view it, it can do much more advanced optimizations when working with that data. When iterating through that data, it doesn't have to make calculated leaps through memory. Instead, it knows exactly how far to move ahead in memory to find the next data point.

As for what Uint8Array is, it's a typed array. Essentially, it tells the compiler/interpreter that you will be accessing this data exclusively as 8-bit uints which, again, allows it to make better optimizations. Then you can use standard array indexing on it (arr[0], arr[1], etc.) and you'll be getting back the equivalent uint values out of the array.

TL;DR They take less space when the exact data format is known, allows you to move more exactly through your data and gives the compiler/interpreter greater options for optimization.

🌐
Mozilla
developer.mozilla.org › en-US › docs › Web › JavaScript › Guide › Typed_arrays
JavaScript typed arrays - JavaScript | MDN
const buffer = new ArrayBuffer(24); // … read the data into the buffer … const idView = new Uint32Array(buffer, 0, 1); const usernameView = new Uint8Array(buffer, 4, 16); const amountDueView = new Float32Array(buffer, 20, 1); Then you can access, for example, the amount due with amountDueView[0]. Note: The data structure alignment in a C structure is platform-dependent.
🌐
Bun
bun.sh › guides › binary › arraybuffer-to-typedarray
Convert an ArrayBuffer to a Uint8Array - Bun
A Uint8Array is a typed array, meaning it is a mechanism for viewing the data in an underlying ArrayBuffer.
🌐
Reddit
reddit.com › r/typescript › you shouldn't be allowed to pass uint8array when arraybuffer is expected ...
r/typescript on Reddit: You shouldn't be allowed to pass Uint8Array when ArrayBuffer is expected ...
December 14, 2024 -

It doesn't make sense to allow being able to assign Uint8Array (Uint16Array, Uint32Array, etc.) to an ArrayBuffer.

What's a good way to enforce that with types?

Or maybe there is a type that only accepts ArrayBufer and excludes TypedArrays (like Uint8Array)?

As you can see here, it is currently possible:

https://www.typescriptlang.org/play/?#code/LAKALgngDgpgBAMQPZLgXjgQQE7YIYQBCArgGakzZwwAeYMAdgCYDOcAqgJYNgAcO+CHAD8cAEQQYLMXABc4hkjEBuUJFiIUAJnQdufAQWp1GrLLgIlylEeMnS5CpapCgANjDBwAbvOSoMMUUVd084Bj9tXQkpENcQAGMkBhYvGnlDIjIKKgwGGAB3PR5+CwgACgBtABYtAF0AShcklK8IeS4SzN18osyrHPLapqA

🌐
Observable
observablehq.com › @julesblm › typed-arrays-and-arraybuffers-too
Typed Arrays and ArrayBuffers / Jules Blom
Observable · Sign in · Typed Arrays and ArrayBuffers | Jules Blom | Observable · Public · Jul 2 · Tinker · •ojs
🌐
MDN Web Docs
developer.mozilla.org › en-US › docs › Web › JavaScript › Reference › Global_Objects › Uint8Array
Uint8Array - JavaScript - MDN Web Docs
The Uint8Array typed array represents an array of 8-bit unsigned integers. The contents are initialized to 0 unless initialization data is explicitly provided. Once established, you can reference elements in the array using the object's methods, or using standard array index syntax (that is, ...
🌐
GitHub
github.com › timostamm › protobuf-ts › issues › 738
Type usages of Uint8Array as Uint8Array<ArrayBuffer> · Issue #738 · timostamm/protobuf-ts
December 7, 2025 - Describe the bug With the most recent version of TypeScript, there was a change to make the type of Uint8Array such that the buffer can be either ArrayBuffer or SharedArrayBuffer. While controversial, it seems as though this change will stick.
Author: timostamm