<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Josephine Anucia</title>
    <description>The latest articles on DEV Community by Josephine Anucia (@jsoneditorfree).</description>
    <link>https://dev.to/jsoneditorfree</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4199961%2F0cedd435-3b74-4383-b467-024b20b53ad8.png</url>
      <title>DEV Community: Josephine Anucia</title>
      <link>https://dev.to/jsoneditorfree</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jsoneditorfree"/>
    <language>en</language>
    <item>
      <title>How we open a 4 GB JSON file in a browser tab without running out of memory</title>
      <dc:creator>Josephine Anucia</dc:creator>
      <pubDate>Thu, 22 Oct 2026 08:07:26 +0000</pubDate>
      <link>https://dev.to/jsoneditorfree/how-we-open-a-4-gb-json-file-in-a-browser-tab-without-running-out-of-memory-58df</link>
      <guid>https://dev.to/jsoneditorfree/how-we-open-a-4-gb-json-file-in-a-browser-tab-without-running-out-of-memory-58df</guid>
      <description>&lt;p&gt;Most online JSON tools fall over somewhere between 50 and 500 MB. The reason is simple: &lt;code&gt;JSON.parse&lt;/code&gt; (or any parser&lt;br&gt;
that builds a tree) turns every value into a JavaScript object. We measured our own lossless parser at about 13&lt;br&gt;
bytes of heap for every byte of JSON. Chrome gives a tab a heap of about 4 GB, so the ceiling sat near 300 MB.&lt;/p&gt;

&lt;p&gt;Here is how &lt;a href="https://jsoneditorfree.com/" rel="noopener noreferrer"&gt;JSON Editor Free&lt;/a&gt; now opens files of up to 4 GB.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Never build the tree
&lt;/h2&gt;

&lt;p&gt;Over 100 MB, the file stays a &lt;code&gt;File&lt;/code&gt;. A worker reads it in 8 MB slices (&lt;code&gt;file.slice(a, b).arrayBuffer()&lt;/code&gt;) and feeds&lt;br&gt;
them to a resumable byte tokenizer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It tracks the JSON grammar: objects, arrays, strings, escapes, numbers, literals.&lt;/li&gt;
&lt;li&gt;It reports token offsets to a handler, but never creates a value.&lt;/li&gt;
&lt;li&gt;It is a state machine, so a token can straddle two chunks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That one pass proves the file is valid JSON and reports the line and column if it is not.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Index only what is big
&lt;/h2&gt;

&lt;p&gt;The handler keeps only containers that span 64 KB or more. For each one it records:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;where it starts and ends;&lt;/li&gt;
&lt;li&gt;how many children it has;&lt;/li&gt;
&lt;li&gt;the byte offset of every 64th child.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It also keeps strings of 64 KB or more. For a 1 GB array of 4.6 million records, that index is about 300 KB.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Read rows on demand
&lt;/h2&gt;

&lt;p&gt;Tree view is virtualised, so it only ever asks for "rows 120,400 to 120,480".&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The row model knows which containers are expanded and how many rows each contributes, so it can map a row
number to "children 120,399 to 120,479 of &lt;code&gt;/data&lt;/code&gt;".&lt;/li&gt;
&lt;li&gt;It jumps to the nearest checkpoint (child 120,384) and scans forward a few kilobytes.&lt;/li&gt;
&lt;li&gt;It skips any big child in one step, using the index.&lt;/li&gt;
&lt;li&gt;Each small value is then parsed with the normal lossless parser, so rows look exactly like they do for small
files.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  4. Search without an index
&lt;/h2&gt;

&lt;p&gt;Search is a single streaming pass over the bytes. A tiny state machine knows whether each byte is inside a string,&lt;br&gt;
a number or between tokens, so a match never spans two values. Only the current match is turned into a JSON&lt;br&gt;
pointer, by walking down from the root with the same checkpoints.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Edit a part, not the whole
&lt;/h2&gt;

&lt;p&gt;Editing 4 GB in place is a different project, so huge files are view-only. You can select any value of up to 50 MB&lt;br&gt;
and open it in the other panel as a normal document, with format, sort, transform, compare and save.&lt;/p&gt;

&lt;h2&gt;
  
  
  Results (desktop Chrome, laptop)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;File&lt;/th&gt;
&lt;th&gt;Open (check + index)&lt;/th&gt;
&lt;th&gt;Search&lt;/th&gt;
&lt;th&gt;Renderer memory&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1 GB&lt;/td&gt;
&lt;td&gt;~5–7 s&lt;/td&gt;
&lt;td&gt;~5–8 s&lt;/td&gt;
&lt;td&gt;~400–700 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2 GB&lt;/td&gt;
&lt;td&gt;~11–14 s&lt;/td&gt;
&lt;td&gt;~10–15 s&lt;/td&gt;
&lt;td&gt;~400–700 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4 GB&lt;/td&gt;
&lt;td&gt;~20 s&lt;/td&gt;
&lt;td&gt;~21 s&lt;/td&gt;
&lt;td&gt;~700 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Try it with your own biggest file: &lt;a href="https://jsoneditorfree.com/" rel="noopener noreferrer"&gt;https://jsoneditorfree.com/&lt;/a&gt;. It's free, with no account, and the file is read on&lt;br&gt;
your device.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>performance</category>
      <category>json</category>
    </item>
  </channel>
</rss>
