[{"data":1,"prerenderedAt":1480},["ShallowReactive",2],{"guide-handling-large-csv-files-browsers":3},{"id":4,"title":5,"body":6,"date":1472,"description":1473,"extension":1474,"meta":1475,"navigation":158,"path":1476,"readingTime":136,"seo":1477,"stem":1478,"__hash__":1479},"guides\u002Fguides\u002Fhandling-large-csv-files-browsers.md","Handling Large CSV Files in Browsers",{"type":7,"value":8,"toc":1461},"minimark",[9,14,18,26,30,33,409,412,416,419,422,708,711,715,718,721,989,1000,1004,1015,1146,1149,1153,1156,1189,1328,1331,1335,1413,1416,1420,1444,1448,1457],[10,11,13],"h2",{"id":12},"the-browser-memory-problem","The Browser Memory Problem",[15,16,17],"p",{},"A 100 MB CSV file expands to roughly 300-500 MB in JavaScript memory after parsing — each string, number, and object adds overhead. Loading the entire file into memory at once can crash the browser tab or freeze the UI for seconds.",[15,19,20,21,25],{},"The solution: ",[22,23,24],"strong",{},"process the file incrementally",", never holding the entire dataset in memory at once.",[10,27,29],{"id":28},"strategy-1-stream-based-parsing","Strategy 1: Stream-Based Parsing",[15,31,32],{},"Instead of reading the whole file into a string and splitting on newlines, read it in chunks and parse incrementally.",[34,35,40],"pre",{"className":36,"code":37,"language":38,"meta":39,"style":39},"language-javascript shiki shiki-themes github-light github-dark","async function parseCSV(file, onRow) {\n  const stream = file.stream();\n  const reader = stream.getReader();\n  const decoder = new TextDecoder();\n  let buffer = '';\n\n  while (true) {\n    const { done, value } = await reader.read();\n    if (done) break;\n\n    buffer += decoder.decode(value, { stream: true });\n    const lines = buffer.split('\\n');\n\n    \u002F\u002F Keep the last incomplete line in the buffer\n    buffer = lines.pop();\n\n    for (const line of lines) {\n      const row = parseRow(line);\n      if (row) onRow(row);\n    }\n  }\n\n  \u002F\u002F Process any remaining data\n  if (buffer) onRow(parseRow(buffer));\n}\n","javascript","",[41,42,43,76,98,116,134,153,160,174,207,221,226,249,278,283,290,305,310,330,347,361,367,373,378,384,403],"code",{"__ignoreMap":39},[44,45,48,52,55,59,63,67,70,73],"span",{"class":46,"line":47},"line",1,[44,49,51],{"class":50},"szBVR","async",[44,53,54],{"class":50}," function",[44,56,58],{"class":57},"sScJk"," parseCSV",[44,60,62],{"class":61},"sVt8B","(",[44,64,66],{"class":65},"s4XuR","file",[44,68,69],{"class":61},", ",[44,71,72],{"class":65},"onRow",[44,74,75],{"class":61},") {\n",[44,77,79,82,86,89,92,95],{"class":46,"line":78},2,[44,80,81],{"class":50},"  const",[44,83,85],{"class":84},"sj4cs"," stream",[44,87,88],{"class":50}," =",[44,90,91],{"class":61}," file.",[44,93,94],{"class":57},"stream",[44,96,97],{"class":61},"();\n",[44,99,101,103,106,108,111,114],{"class":46,"line":100},3,[44,102,81],{"class":50},[44,104,105],{"class":84}," reader",[44,107,88],{"class":50},[44,109,110],{"class":61}," stream.",[44,112,113],{"class":57},"getReader",[44,115,97],{"class":61},[44,117,119,121,124,126,129,132],{"class":46,"line":118},4,[44,120,81],{"class":50},[44,122,123],{"class":84}," decoder",[44,125,88],{"class":50},[44,127,128],{"class":50}," new",[44,130,131],{"class":57}," TextDecoder",[44,133,97],{"class":61},[44,135,137,140,143,146,150],{"class":46,"line":136},5,[44,138,139],{"class":50},"  let",[44,141,142],{"class":61}," buffer ",[44,144,145],{"class":50},"=",[44,147,149],{"class":148},"sZZnC"," ''",[44,151,152],{"class":61},";\n",[44,154,156],{"class":46,"line":155},6,[44,157,159],{"emptyLinePlaceholder":158},true,"\n",[44,161,163,166,169,172],{"class":46,"line":162},7,[44,164,165],{"class":50},"  while",[44,167,168],{"class":61}," (",[44,170,171],{"class":84},"true",[44,173,75],{"class":61},[44,175,177,180,183,186,188,191,194,196,199,202,205],{"class":46,"line":176},8,[44,178,179],{"class":50},"    const",[44,181,182],{"class":61}," { ",[44,184,185],{"class":84},"done",[44,187,69],{"class":61},[44,189,190],{"class":84},"value",[44,192,193],{"class":61}," } ",[44,195,145],{"class":50},[44,197,198],{"class":50}," await",[44,200,201],{"class":61}," reader.",[44,203,204],{"class":57},"read",[44,206,97],{"class":61},[44,208,210,213,216,219],{"class":46,"line":209},9,[44,211,212],{"class":50},"    if",[44,214,215],{"class":61}," (done) ",[44,217,218],{"class":50},"break",[44,220,152],{"class":61},[44,222,224],{"class":46,"line":223},10,[44,225,159],{"emptyLinePlaceholder":158},[44,227,229,232,235,238,241,244,246],{"class":46,"line":228},11,[44,230,231],{"class":61},"    buffer ",[44,233,234],{"class":50},"+=",[44,236,237],{"class":61}," decoder.",[44,239,240],{"class":57},"decode",[44,242,243],{"class":61},"(value, { stream: ",[44,245,171],{"class":84},[44,247,248],{"class":61}," });\n",[44,250,252,254,257,259,262,265,267,270,273,275],{"class":46,"line":251},12,[44,253,179],{"class":50},[44,255,256],{"class":84}," lines",[44,258,88],{"class":50},[44,260,261],{"class":61}," buffer.",[44,263,264],{"class":57},"split",[44,266,62],{"class":61},[44,268,269],{"class":148},"'",[44,271,272],{"class":84},"\\n",[44,274,269],{"class":148},[44,276,277],{"class":61},");\n",[44,279,281],{"class":46,"line":280},13,[44,282,159],{"emptyLinePlaceholder":158},[44,284,286],{"class":46,"line":285},14,[44,287,289],{"class":288},"sJ8bj","    \u002F\u002F Keep the last incomplete line in the buffer\n",[44,291,293,295,297,300,303],{"class":46,"line":292},15,[44,294,231],{"class":61},[44,296,145],{"class":50},[44,298,299],{"class":61}," lines.",[44,301,302],{"class":57},"pop",[44,304,97],{"class":61},[44,306,308],{"class":46,"line":307},16,[44,309,159],{"emptyLinePlaceholder":158},[44,311,313,316,318,321,324,327],{"class":46,"line":312},17,[44,314,315],{"class":50},"    for",[44,317,168],{"class":61},[44,319,320],{"class":50},"const",[44,322,323],{"class":84}," line",[44,325,326],{"class":50}," of",[44,328,329],{"class":61}," lines) {\n",[44,331,333,336,339,341,344],{"class":46,"line":332},18,[44,334,335],{"class":50},"      const",[44,337,338],{"class":84}," row",[44,340,88],{"class":50},[44,342,343],{"class":57}," parseRow",[44,345,346],{"class":61},"(line);\n",[44,348,350,353,356,358],{"class":46,"line":349},19,[44,351,352],{"class":50},"      if",[44,354,355],{"class":61}," (row) ",[44,357,72],{"class":57},[44,359,360],{"class":61},"(row);\n",[44,362,364],{"class":46,"line":363},20,[44,365,366],{"class":61},"    }\n",[44,368,370],{"class":46,"line":369},21,[44,371,372],{"class":61},"  }\n",[44,374,376],{"class":46,"line":375},22,[44,377,159],{"emptyLinePlaceholder":158},[44,379,381],{"class":46,"line":380},23,[44,382,383],{"class":288},"  \u002F\u002F Process any remaining data\n",[44,385,387,390,393,395,397,400],{"class":46,"line":386},24,[44,388,389],{"class":50},"  if",[44,391,392],{"class":61}," (buffer) ",[44,394,72],{"class":57},[44,396,62],{"class":61},[44,398,399],{"class":57},"parseRow",[44,401,402],{"class":61},"(buffer));\n",[44,404,406],{"class":46,"line":405},25,[44,407,408],{"class":61},"}\n",[15,410,411],{},"This approach holds at most one chunk of text plus one incomplete line in memory — constant space regardless of file size.",[10,413,415],{"id":414},"strategy-2-web-workers-for-cpu-heavy-parsing","Strategy 2: Web Workers for CPU-Heavy Parsing",[15,417,418],{},"Parsing is CPU-intensive. Running it on the main thread blocks the UI — buttons stop responding, animations freeze, and the browser may show a \"page unresponsive\" dialog.",[15,420,421],{},"Move parsing to a Web Worker:",[34,423,425],{"className":36,"code":424,"language":38,"meta":39,"style":39},"\u002F\u002F main.js\nconst worker = new Worker('csv-worker.js');\n\nworker.postMessage({ file });\nworker.onmessage = (e) => {\n  if (e.data.type === 'row') {\n    appendRowToTable(e.data.row);\n  } else if (e.data.type === 'done') {\n    console.log(`Processed ${e.data.count} rows`);\n  }\n};\n\n\u002F\u002F csv-worker.js\nself.onmessage = async (e) => {\n  const file = e.data.file;\n  let count = 0;\n\n  await parseCSV(file, (row) => {\n    self.postMessage({ type: 'row', row });\n    count++;\n  });\n\n  self.postMessage({ type: 'done', count });\n};\n",[41,426,427,432,453,457,468,491,506,514,534,565,569,574,578,583,605,617,631,635,654,670,680,685,689,704],{"__ignoreMap":39},[44,428,429],{"class":46,"line":47},[44,430,431],{"class":288},"\u002F\u002F main.js\n",[44,433,434,436,439,441,443,446,448,451],{"class":46,"line":78},[44,435,320],{"class":50},[44,437,438],{"class":84}," worker",[44,440,88],{"class":50},[44,442,128],{"class":50},[44,444,445],{"class":57}," Worker",[44,447,62],{"class":61},[44,449,450],{"class":148},"'csv-worker.js'",[44,452,277],{"class":61},[44,454,455],{"class":46,"line":100},[44,456,159],{"emptyLinePlaceholder":158},[44,458,459,462,465],{"class":46,"line":118},[44,460,461],{"class":61},"worker.",[44,463,464],{"class":57},"postMessage",[44,466,467],{"class":61},"({ file });\n",[44,469,470,472,475,477,479,482,485,488],{"class":46,"line":136},[44,471,461],{"class":61},[44,473,474],{"class":57},"onmessage",[44,476,88],{"class":50},[44,478,168],{"class":61},[44,480,481],{"class":65},"e",[44,483,484],{"class":61},") ",[44,486,487],{"class":50},"=>",[44,489,490],{"class":61}," {\n",[44,492,493,495,498,501,504],{"class":46,"line":155},[44,494,389],{"class":50},[44,496,497],{"class":61}," (e.data.type ",[44,499,500],{"class":50},"===",[44,502,503],{"class":148}," 'row'",[44,505,75],{"class":61},[44,507,508,511],{"class":46,"line":162},[44,509,510],{"class":57},"    appendRowToTable",[44,512,513],{"class":61},"(e.data.row);\n",[44,515,516,519,522,525,527,529,532],{"class":46,"line":176},[44,517,518],{"class":61},"  } ",[44,520,521],{"class":50},"else",[44,523,524],{"class":50}," if",[44,526,497],{"class":61},[44,528,500],{"class":50},[44,530,531],{"class":148}," 'done'",[44,533,75],{"class":61},[44,535,536,539,542,544,547,549,552,555,557,560,563],{"class":46,"line":209},[44,537,538],{"class":61},"    console.",[44,540,541],{"class":57},"log",[44,543,62],{"class":61},[44,545,546],{"class":148},"`Processed ${",[44,548,481],{"class":61},[44,550,551],{"class":148},".",[44,553,554],{"class":61},"data",[44,556,551],{"class":148},[44,558,559],{"class":61},"count",[44,561,562],{"class":148},"} rows`",[44,564,277],{"class":61},[44,566,567],{"class":46,"line":223},[44,568,372],{"class":61},[44,570,571],{"class":46,"line":228},[44,572,573],{"class":61},"};\n",[44,575,576],{"class":46,"line":251},[44,577,159],{"emptyLinePlaceholder":158},[44,579,580],{"class":46,"line":280},[44,581,582],{"class":288},"\u002F\u002F csv-worker.js\n",[44,584,585,588,590,592,595,597,599,601,603],{"class":46,"line":285},[44,586,587],{"class":61},"self.",[44,589,474],{"class":57},[44,591,88],{"class":50},[44,593,594],{"class":50}," async",[44,596,168],{"class":61},[44,598,481],{"class":65},[44,600,484],{"class":61},[44,602,487],{"class":50},[44,604,490],{"class":61},[44,606,607,609,612,614],{"class":46,"line":292},[44,608,81],{"class":50},[44,610,611],{"class":84}," file",[44,613,88],{"class":50},[44,615,616],{"class":61}," e.data.file;\n",[44,618,619,621,624,626,629],{"class":46,"line":307},[44,620,139],{"class":50},[44,622,623],{"class":61}," count ",[44,625,145],{"class":50},[44,627,628],{"class":84}," 0",[44,630,152],{"class":61},[44,632,633],{"class":46,"line":312},[44,634,159],{"emptyLinePlaceholder":158},[44,636,637,640,642,645,648,650,652],{"class":46,"line":332},[44,638,639],{"class":50},"  await",[44,641,58],{"class":57},[44,643,644],{"class":61},"(file, (",[44,646,647],{"class":65},"row",[44,649,484],{"class":61},[44,651,487],{"class":50},[44,653,490],{"class":61},[44,655,656,659,661,664,667],{"class":46,"line":349},[44,657,658],{"class":61},"    self.",[44,660,464],{"class":57},[44,662,663],{"class":61},"({ type: ",[44,665,666],{"class":148},"'row'",[44,668,669],{"class":61},", row });\n",[44,671,672,675,678],{"class":46,"line":363},[44,673,674],{"class":61},"    count",[44,676,677],{"class":50},"++",[44,679,152],{"class":61},[44,681,682],{"class":46,"line":369},[44,683,684],{"class":61},"  });\n",[44,686,687],{"class":46,"line":375},[44,688,159],{"emptyLinePlaceholder":158},[44,690,691,694,696,698,701],{"class":46,"line":380},[44,692,693],{"class":61},"  self.",[44,695,464],{"class":57},[44,697,663],{"class":61},[44,699,700],{"class":148},"'done'",[44,702,703],{"class":61},", count });\n",[44,705,706],{"class":46,"line":386},[44,707,573],{"class":61},[15,709,710],{},"The main thread stays responsive. The worker handles parsing in the background.",[10,712,714],{"id":713},"strategy-3-virtual-scrolling-for-display","Strategy 3: Virtual Scrolling for Display",[15,716,717],{},"Even if you parse efficiently, rendering 100,000 rows in the DOM crashes the browser. Each DOM node consumes memory and triggers layout calculations.",[15,719,720],{},"Virtual scrolling renders only the visible rows:",[34,722,724],{"className":36,"code":723,"language":38,"meta":39,"style":39},"function renderVisibleRows(container, allRows, scrollTop, rowHeight) {\n  const visibleCount = Math.ceil(container.clientHeight \u002F rowHeight);\n  const startIndex = Math.floor(scrollTop \u002F rowHeight);\n  const endIndex = Math.min(startIndex + visibleCount, allRows.length);\n\n  \u002F\u002F Render only rows in the viewport\n  const fragment = document.createDocumentFragment();\n  for (let i = startIndex; i \u003C endIndex; i++) {\n    const row = createRowElement(allRows[i]);\n    row.style.transform = `translateY(${i * rowHeight}px)`;\n    fragment.appendChild(row);\n  }\n\n  container.innerHTML = '';\n  container.appendChild(fragment);\n  container.style.height = `${allRows.length * rowHeight}px`;\n}\n",[41,725,726,756,780,801,829,833,838,855,883,897,921,931,935,939,950,960,985],{"__ignoreMap":39},[44,727,728,731,734,736,739,741,744,746,749,751,754],{"class":46,"line":47},[44,729,730],{"class":50},"function",[44,732,733],{"class":57}," renderVisibleRows",[44,735,62],{"class":61},[44,737,738],{"class":65},"container",[44,740,69],{"class":61},[44,742,743],{"class":65},"allRows",[44,745,69],{"class":61},[44,747,748],{"class":65},"scrollTop",[44,750,69],{"class":61},[44,752,753],{"class":65},"rowHeight",[44,755,75],{"class":61},[44,757,758,760,763,765,768,771,774,777],{"class":46,"line":78},[44,759,81],{"class":50},[44,761,762],{"class":84}," visibleCount",[44,764,88],{"class":50},[44,766,767],{"class":61}," Math.",[44,769,770],{"class":57},"ceil",[44,772,773],{"class":61},"(container.clientHeight ",[44,775,776],{"class":50},"\u002F",[44,778,779],{"class":61}," rowHeight);\n",[44,781,782,784,787,789,791,794,797,799],{"class":46,"line":100},[44,783,81],{"class":50},[44,785,786],{"class":84}," startIndex",[44,788,88],{"class":50},[44,790,767],{"class":61},[44,792,793],{"class":57},"floor",[44,795,796],{"class":61},"(scrollTop ",[44,798,776],{"class":50},[44,800,779],{"class":61},[44,802,803,805,808,810,812,815,818,821,824,827],{"class":46,"line":118},[44,804,81],{"class":50},[44,806,807],{"class":84}," endIndex",[44,809,88],{"class":50},[44,811,767],{"class":61},[44,813,814],{"class":57},"min",[44,816,817],{"class":61},"(startIndex ",[44,819,820],{"class":50},"+",[44,822,823],{"class":61}," visibleCount, allRows.",[44,825,826],{"class":84},"length",[44,828,277],{"class":61},[44,830,831],{"class":46,"line":136},[44,832,159],{"emptyLinePlaceholder":158},[44,834,835],{"class":46,"line":155},[44,836,837],{"class":288},"  \u002F\u002F Render only rows in the viewport\n",[44,839,840,842,845,847,850,853],{"class":46,"line":162},[44,841,81],{"class":50},[44,843,844],{"class":84}," fragment",[44,846,88],{"class":50},[44,848,849],{"class":61}," document.",[44,851,852],{"class":57},"createDocumentFragment",[44,854,97],{"class":61},[44,856,857,860,862,865,868,870,873,876,879,881],{"class":46,"line":176},[44,858,859],{"class":50},"  for",[44,861,168],{"class":61},[44,863,864],{"class":50},"let",[44,866,867],{"class":61}," i ",[44,869,145],{"class":50},[44,871,872],{"class":61}," startIndex; i ",[44,874,875],{"class":50},"\u003C",[44,877,878],{"class":61}," endIndex; i",[44,880,677],{"class":50},[44,882,75],{"class":61},[44,884,885,887,889,891,894],{"class":46,"line":209},[44,886,179],{"class":50},[44,888,338],{"class":84},[44,890,88],{"class":50},[44,892,893],{"class":57}," createRowElement",[44,895,896],{"class":61},"(allRows[i]);\n",[44,898,899,902,904,907,910,913,916,919],{"class":46,"line":223},[44,900,901],{"class":61},"    row.style.transform ",[44,903,145],{"class":50},[44,905,906],{"class":148}," `translateY(${",[44,908,909],{"class":61},"i",[44,911,912],{"class":50}," *",[44,914,915],{"class":61}," rowHeight",[44,917,918],{"class":148},"}px)`",[44,920,152],{"class":61},[44,922,923,926,929],{"class":46,"line":228},[44,924,925],{"class":61},"    fragment.",[44,927,928],{"class":57},"appendChild",[44,930,360],{"class":61},[44,932,933],{"class":46,"line":251},[44,934,372],{"class":61},[44,936,937],{"class":46,"line":280},[44,938,159],{"emptyLinePlaceholder":158},[44,940,941,944,946,948],{"class":46,"line":285},[44,942,943],{"class":61},"  container.innerHTML ",[44,945,145],{"class":50},[44,947,149],{"class":148},[44,949,152],{"class":61},[44,951,952,955,957],{"class":46,"line":292},[44,953,954],{"class":61},"  container.",[44,956,928],{"class":57},[44,958,959],{"class":61},"(fragment);\n",[44,961,962,965,967,970,972,974,976,978,980,983],{"class":46,"line":307},[44,963,964],{"class":61},"  container.style.height ",[44,966,145],{"class":50},[44,968,969],{"class":148}," `${",[44,971,743],{"class":61},[44,973,551],{"class":148},[44,975,826],{"class":84},[44,977,912],{"class":50},[44,979,915],{"class":61},[44,981,982],{"class":148},"}px`",[44,984,152],{"class":61},[44,986,987],{"class":46,"line":312},[44,988,408],{"class":61},[15,990,991,992,995,996,999],{},"Libraries like ",[41,993,994],{},"tanstack\u002Fvirtual"," or ",[41,997,998],{},"react-virtualized"," handle this pattern for you.",[10,1001,1003],{"id":1002},"strategy-4-chunked-file-reading","Strategy 4: Chunked File Reading",[15,1005,1006,1007,1010,1011,1014],{},"For files over 50 MB, avoid ",[41,1008,1009],{},"FileReader.readAsText()"," — it loads the entire file into a string. Use ",[41,1012,1013],{},"File.slice()"," to read in controlled chunks:",[34,1016,1018],{"className":36,"code":1017,"language":38,"meta":39,"style":39},"async function readFileInChunks(file, chunkSize = 5 * 1024 * 1024) {\n  let offset = 0;\n  while (offset \u003C file.size) {\n    const chunk = file.slice(offset, offset + chunkSize);\n    const text = await chunk.text();\n    processChunk(text);\n    offset += chunkSize;\n  }\n}\n",[41,1019,1020,1054,1067,1079,1101,1120,1128,1138,1142],{"__ignoreMap":39},[44,1021,1022,1024,1026,1029,1031,1033,1035,1038,1040,1043,1045,1048,1050,1052],{"class":46,"line":47},[44,1023,51],{"class":50},[44,1025,54],{"class":50},[44,1027,1028],{"class":57}," readFileInChunks",[44,1030,62],{"class":61},[44,1032,66],{"class":65},[44,1034,69],{"class":61},[44,1036,1037],{"class":65},"chunkSize",[44,1039,88],{"class":50},[44,1041,1042],{"class":84}," 5",[44,1044,912],{"class":50},[44,1046,1047],{"class":84}," 1024",[44,1049,912],{"class":50},[44,1051,1047],{"class":84},[44,1053,75],{"class":61},[44,1055,1056,1058,1061,1063,1065],{"class":46,"line":78},[44,1057,139],{"class":50},[44,1059,1060],{"class":61}," offset ",[44,1062,145],{"class":50},[44,1064,628],{"class":84},[44,1066,152],{"class":61},[44,1068,1069,1071,1074,1076],{"class":46,"line":100},[44,1070,165],{"class":50},[44,1072,1073],{"class":61}," (offset ",[44,1075,875],{"class":50},[44,1077,1078],{"class":61}," file.size) {\n",[44,1080,1081,1083,1086,1088,1090,1093,1096,1098],{"class":46,"line":118},[44,1082,179],{"class":50},[44,1084,1085],{"class":84}," chunk",[44,1087,88],{"class":50},[44,1089,91],{"class":61},[44,1091,1092],{"class":57},"slice",[44,1094,1095],{"class":61},"(offset, offset ",[44,1097,820],{"class":50},[44,1099,1100],{"class":61}," chunkSize);\n",[44,1102,1103,1105,1108,1110,1112,1115,1118],{"class":46,"line":136},[44,1104,179],{"class":50},[44,1106,1107],{"class":84}," text",[44,1109,88],{"class":50},[44,1111,198],{"class":50},[44,1113,1114],{"class":61}," chunk.",[44,1116,1117],{"class":57},"text",[44,1119,97],{"class":61},[44,1121,1122,1125],{"class":46,"line":155},[44,1123,1124],{"class":57},"    processChunk",[44,1126,1127],{"class":61},"(text);\n",[44,1129,1130,1133,1135],{"class":46,"line":162},[44,1131,1132],{"class":61},"    offset ",[44,1134,234],{"class":50},[44,1136,1137],{"class":61}," chunkSize;\n",[44,1139,1140],{"class":46,"line":176},[44,1141,372],{"class":61},[44,1143,1144],{"class":46,"line":209},[44,1145,408],{"class":61},[15,1147,1148],{},"This lets you update a progress bar and gives the browser time to garbage-collect between chunks.",[10,1150,1152],{"id":1151},"combining-all-strategies","Combining All Strategies",[15,1154,1155],{},"A production-grade CSV viewer combines all three:",[1157,1158,1159,1171,1177,1183],"ol",{},[1160,1161,1162,1165,1166,995,1168],"li",{},[22,1163,1164],{},"Read"," the file in chunks using ",[41,1167,1013],{},[41,1169,1170],{},"file.stream()",[1160,1172,1173,1176],{},[22,1174,1175],{},"Parse"," rows in a Web Worker to keep the UI responsive",[1160,1178,1179,1182],{},[22,1180,1181],{},"Render"," rows using virtual scrolling to limit DOM nodes",[1160,1184,1185,1188],{},[22,1186,1187],{},"Aggregate"," summary statistics incrementally instead of storing all rows",[34,1190,1192],{"className":36,"code":1191,"language":38,"meta":39,"style":39},"let stats = { total: 0, sumByColumn: {} };\n\nawait parseCSV(file, (row) => {\n  stats.total++;\n  Object.entries(row).forEach(([col, val]) => {\n    if (typeof val === 'number') {\n      stats.sumByColumn[col] = (stats.sumByColumn[col] || 0) + val;\n    }\n  });\n});\n",[41,1193,1194,1212,1216,1233,1242,1274,1293,1315,1319,1323],{"__ignoreMap":39},[44,1195,1196,1198,1201,1203,1206,1209],{"class":46,"line":47},[44,1197,864],{"class":50},[44,1199,1200],{"class":61}," stats ",[44,1202,145],{"class":50},[44,1204,1205],{"class":61}," { total: ",[44,1207,1208],{"class":84},"0",[44,1210,1211],{"class":61},", sumByColumn: {} };\n",[44,1213,1214],{"class":46,"line":78},[44,1215,159],{"emptyLinePlaceholder":158},[44,1217,1218,1221,1223,1225,1227,1229,1231],{"class":46,"line":100},[44,1219,1220],{"class":50},"await",[44,1222,58],{"class":57},[44,1224,644],{"class":61},[44,1226,647],{"class":65},[44,1228,484],{"class":61},[44,1230,487],{"class":50},[44,1232,490],{"class":61},[44,1234,1235,1238,1240],{"class":46,"line":118},[44,1236,1237],{"class":61},"  stats.total",[44,1239,677],{"class":50},[44,1241,152],{"class":61},[44,1243,1244,1247,1250,1253,1256,1259,1262,1264,1267,1270,1272],{"class":46,"line":136},[44,1245,1246],{"class":61},"  Object.",[44,1248,1249],{"class":57},"entries",[44,1251,1252],{"class":61},"(row).",[44,1254,1255],{"class":57},"forEach",[44,1257,1258],{"class":61},"(([",[44,1260,1261],{"class":65},"col",[44,1263,69],{"class":61},[44,1265,1266],{"class":65},"val",[44,1268,1269],{"class":61},"]) ",[44,1271,487],{"class":50},[44,1273,490],{"class":61},[44,1275,1276,1278,1280,1283,1286,1288,1291],{"class":46,"line":155},[44,1277,212],{"class":50},[44,1279,168],{"class":61},[44,1281,1282],{"class":50},"typeof",[44,1284,1285],{"class":61}," val ",[44,1287,500],{"class":50},[44,1289,1290],{"class":148}," 'number'",[44,1292,75],{"class":61},[44,1294,1295,1298,1300,1303,1306,1308,1310,1312],{"class":46,"line":162},[44,1296,1297],{"class":61},"      stats.sumByColumn[col] ",[44,1299,145],{"class":50},[44,1301,1302],{"class":61}," (stats.sumByColumn[col] ",[44,1304,1305],{"class":50},"||",[44,1307,628],{"class":84},[44,1309,484],{"class":61},[44,1311,820],{"class":50},[44,1313,1314],{"class":61}," val;\n",[44,1316,1317],{"class":46,"line":176},[44,1318,366],{"class":61},[44,1320,1321],{"class":46,"line":209},[44,1322,684],{"class":61},[44,1324,1325],{"class":46,"line":223},[44,1326,1327],{"class":61},"});\n",[15,1329,1330],{},"This computes totals, averages, and counts without ever storing the full dataset.",[10,1332,1334],{"id":1333},"performance-benchmarks","Performance Benchmarks",[1336,1337,1338,1357],"table",{},[1339,1340,1341],"thead",{},[1342,1343,1344,1348,1351,1354],"tr",{},[1345,1346,1347],"th",{},"File Size",[1345,1349,1350],{},"Naive (readAll)",[1345,1352,1353],{},"Streaming + Worker",[1345,1355,1356],{},"Virtual Scroll Rows",[1358,1359,1360,1375,1388,1401],"tbody",{},[1342,1361,1362,1366,1369,1372],{},[1363,1364,1365],"td",{},"1 MB",[1363,1367,1368],{},"~200ms",[1363,1370,1371],{},"~180ms",[1363,1373,1374],{},"20",[1342,1376,1377,1380,1383,1386],{},[1363,1378,1379],{},"50 MB",[1363,1381,1382],{},"3-5s, UI freezes",[1363,1384,1385],{},"~800ms",[1363,1387,1374],{},[1342,1389,1390,1393,1396,1399],{},[1363,1391,1392],{},"200 MB",[1363,1394,1395],{},"Tab crash",[1363,1397,1398],{},"~3s",[1363,1400,1374],{},[1342,1402,1403,1406,1408,1411],{},[1363,1404,1405],{},"1 GB",[1363,1407,1395],{},[1363,1409,1410],{},"~15s",[1363,1412,1374],{},[15,1414,1415],{},"The DOM node count stays constant at ~20 regardless of file size with virtual scrolling.",[10,1417,1419],{"id":1418},"key-takeaways","Key Takeaways",[1421,1422,1423,1426,1432,1435,1438,1441],"ul",{},[1160,1424,1425],{},"Large CSV files can crash the browser if loaded entirely into memory",[1160,1427,1428,1429,1431],{},"Use streaming APIs (",[41,1430,1170],{},") to parse incrementally — constant memory usage",[1160,1433,1434],{},"Move CPU-heavy parsing to Web Workers to keep the UI responsive",[1160,1436,1437],{},"Virtual scrolling limits DOM nodes to the visible viewport regardless of dataset size",[1160,1439,1440],{},"Compute aggregations incrementally rather than storing all rows in an array",[1160,1442,1443],{},"Combine all strategies for production-grade CSV handling in the browser",[10,1445,1447],{"id":1446},"try-it-yourself","Try It Yourself",[15,1449,1450,1451,1456],{},"Convert CSV files of any size to JSON using our ",[1452,1453,1455],"a",{"href":1454},"\u002Ftools\u002Fcsv-json","CSV to JSON Converter",". Paste or upload your data and get structured JSON output instantly.",[1458,1459,1460],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":39,"searchDepth":78,"depth":78,"links":1462},[1463,1464,1465,1466,1467,1468,1469,1470,1471],{"id":12,"depth":78,"text":13},{"id":28,"depth":78,"text":29},{"id":414,"depth":78,"text":415},{"id":713,"depth":78,"text":714},{"id":1002,"depth":78,"text":1003},{"id":1151,"depth":78,"text":1152},{"id":1333,"depth":78,"text":1334},{"id":1418,"depth":78,"text":1419},{"id":1446,"depth":78,"text":1447},"2026-05-28","Techniques for processing large CSV files in the browser — streaming parsers, Web Workers, and chunked rendering to keep UI responsive.","md",{"immutable":158},"\u002Fguides\u002Fhandling-large-csv-files-browsers",{"title":5,"description":1473},"guides\u002Fhandling-large-csv-files-browsers","9hfq28rrNqI3hnRQQ9UzCMzSC0d-aLuCI6H6wCVTNiQ",1780401334037]