You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This issue is a placeholder to investigate the potential performance gains of LegendList in E/App as opposed to FlashList. Independent metrics suggest it should improve TTI, scroll FPS, and use less memory and CPU.
We are currently discussing how to handle initial chat loading with LegendList in this Slack thread. The current initial report loading is broken and not working holistically, so this needs a better approach anyway.
In my proof of concept, i've created different examples of the LegendList implementation using...
current behavior (rendering what is stored locally, before rendering full dataset)
showing a loading skeleton until fully loaded
showing a loading indicator until fully loaded.
The proof of concept already re-writes all logic in the app that are targeted towards an inverted list, in order to be able to record proper benchmarks with LegendList. There were also issues with the initial scroll that have been fixed now.
I'm currently recording benchmarks between FlashList and LegendList, measuring FPS drops, CPU/RAM usage. Results should be ready today!
A quick update on where we're at with the LegendList migration, benchmarks and testing:
We are currently discussing how to handle initial chat loading with LegendList in this Slack thread.
We still haven't settled on the final UX design for this, but let's discuss further once the LegendList proposal is out and has been accepted!
I've collected benchmarks from automated flows navigating a long chat list. On Android the automations were run and the metrics were recorded using Flashlight and on iOS using XCTest.
Both benchmarks show improvements in CPU/RAM usage and FPS count stays higher than with FlashList.
I'm currently fixing some remaining issues with scrolling behavior and i'm tweaking the knobs around virtualization and recycling, to achieve the best performance across all chats.
Here are some screenshots from the Android Flashlight results:
I've conducted the experiment on a slow (Samsung Galaxy S10e) and fast (Samsung Galaxy S10 5G) Android phone, and on an iPhone 14 Pro. These are the results:
Android
LegendList uses less average CPU and RAM on both Android phones. The FPS and memory improvements are much more noticeable on the slower Galaxy S10e.
Samsung Galaxy S10e (slow)
Metric
FlashList
LegendList
LegendList change
Average FPS
45.7
51.9
13.6% higher
Average CPU
214.9%
180.3%
16.1% lower
Average RAM
766.1 MB
596.4 MB
22.2% lower
High-CPU time
38.0 s
33.5 s
11.8% lower
Flashlight report
Metric overview
FPS Count
Total CPU usage
RN Thread CPU Usage
UI Thread CPU Usage
RAM Usage
Samsung Galaxy S10 5g (fast)
Metric
FlashList
LegendList
LegendList change
Average FPS
52.8
52.7
Essentially unchanged
Average CPU
177.2%
156.9%
11.5% lower
Average RAM
842.2 MB
828.0 MB
1.7% lower
High-CPU time
33.5 s
26.0 s
22.4% lower
On the S10e, LegendList saves approximately 170 MB of RAM and delivers 6.2 more FPS on average. Its FPS graph also shows fewer deep drops during scrolling.
On the S10 5G, the benefit is mainly lower CPU usage. Average FPS is effectively unchanged, and the RAM saving is smaller at approximately 14 MB. The graph includes an early LegendList memory spike, so the improvement is in average RAM, not consistently lower memory at every moment.
These results show better resource usage, especially on the slower phone. They do not show faster overall test completion. CPU percentages can exceed 100% because they include work across multiple cores.
Flashlight report
Metric overview
FPS Count
Total CPU usage
RN Thread CPU Usage
UI Thread CPU Usage
RAM Usage
iOS
A similar XCTest automation exercised opening and scrolling a large chat on an iPhone 14 Pro running iOS 26.6.1. Apple Instruments collected CPU, memory, hangs, and hitches while the test ran.
This setup did not capture FPS. Instead, the Hitches instrument measured delayed frames, and the Hangs instrument recorded brief unresponsiveness lasting more than 100 ms.
I extracted the following values from the supplied .trace file. It contains one recording per implementation. CPU and RAM averages cover each complete recorded window.
Metric
FlashList
LegendList
LegendList change
Average CPU
77.9%
63.8%
18.1% lower
Average RAM footprint
499.0 MiB
396.7 MiB
20.5% lower
Peak RAM footprint
587.6 MiB
423.8 MiB
27.9% lower
Hitch count
35
26
25.7% fewer
Total hitch duration
958.7 ms
1,017.0 ms
6.1% higher
Average hitch duration
27.4 ms
39.1 ms
42.8% longer
Longest hitch
175.0 ms
175.0 ms
Unchanged
Brief hang count
2
2
Unchanged
Total hang duration
354.8 ms
352.6 ms
Essentially unchanged
Recording length
35.74 s
41.26 s
15.4% longer
LegendList used approximately 102 MiB less RAM on average, with a 164 MiB lower peak. Average CPU usage was also lower.
The smoothness result is mixed. LegendList produced fewer hitches, but those hitches lasted longer on average, and their combined duration increased slightly. Both implementations recorded two brief hangs. We should describe this as lower CPU and memory usage with fewer, longer hitches, rather than an improvement in every responsiveness metric.
The recordings have different lengths and were stopped manually, so recording length is not a reliable measure of test completion speed. These results should also remain separate from the earlier five-run XCTest measurements.
Conclusion
These benchmarks support migrating to LegendList: it consistently reduces CPU and memory usage, while improving performance on slower devices and maintaining comparable FPS on faster hardware. The gains are especially valuable for large, complex lists such as ReportActionsList.
Were you able to do it without LegendList patches?
So far i didn't need any patches. I'm going to sort out any remaining issues and edge cases, but i don't think we're going to need to patch the library at all.
The solution for this issue has been 🚀 deployed to production 🚀 in version 9.5.25-2 and is now subject to a 7-day regression period 📆. Here is the list of pull requests that resolve this issue:
The solution for this issue has been 🚀 deployed to production 🚀 in version 9.5.26-1 and is now subject to a 7-day regression period 📆. Here is the list of pull requests that resolve this issue:
Activity
roryabraham commentedon Aug 19, 2026
@chrispader has a draft PR here #98270 and is working on collecting metrics
melvin-bot commentedon Aug 24, 2026
@chrispader Eep! 4 days overdue now. Issues have feelings too...
chrispader commentedon Aug 26, 2026
We are currently discussing how to handle initial chat loading with LegendList in this Slack thread. The current initial report loading is broken and not working holistically, so this needs a better approach anyway.
In my proof of concept, i've created different examples of the LegendList implementation using...
The proof of concept already re-writes all logic in the app that are targeted towards an inverted list, in order to be able to record proper benchmarks with LegendList. There were also issues with the initial scroll that have been fixed now.
I'm currently recording benchmarks between FlashList and LegendList, measuring FPS drops, CPU/RAM usage. Results should be ready today!
chrispader commentedon Aug 31, 2026
A quick update on where we're at with the LegendList migration, benchmarks and testing:
We still haven't settled on the final UX design for this, but let's discuss further once the LegendList proposal is out and has been accepted!
I've collected benchmarks from automated flows navigating a long chat list. On Android the automations were run and the metrics were recorded using Flashlight and on iOS using XCTest.
Both benchmarks show improvements in CPU/RAM usage and FPS count stays higher than with FlashList.
I'm currently fixing some remaining issues with scrolling behavior and i'm tweaking the knobs around virtualization and recycling, to achieve the best performance across all chats.
Here are some screenshots from the Android Flashlight results:
And from another heavier list flow:
chrispader commentedon Aug 31, 2026
Once i've finished the benchmarks and found fixes for the remaining scroll/initial rendering issues, i'm going to post the proposal on Slack 🙌🏼
chrispader commentedon Sep 1, 2026
Benchmarking flow
I've finished my benchmarks for this specific chat flow:
In between each of the scrolls, there is a small wait period. Here's an example video of how this flow was tested on the slow Samsung Galaxy S10e:
Screen_Recording_20260901_222742_Expensify.flashlist.mp4
Screen_Recording_20260901_222833_Expensify.legendlist.mp4
Results
I've conducted the experiment on a slow (Samsung Galaxy S10e) and fast (Samsung Galaxy S10 5G) Android phone, and on an iPhone 14 Pro. These are the results:
Android
LegendList uses less average CPU and RAM on both Android phones. The FPS and memory improvements are much more noticeable on the slower Galaxy S10e.
Samsung Galaxy S10e (slow)
Flashlight report
Samsung Galaxy S10 5g (fast)
On the S10e, LegendList saves approximately 170 MB of RAM and delivers 6.2 more FPS on average. Its FPS graph also shows fewer deep drops during scrolling.
On the S10 5G, the benefit is mainly lower CPU usage. Average FPS is effectively unchanged, and the RAM saving is smaller at approximately 14 MB. The graph includes an early LegendList memory spike, so the improvement is in average RAM, not consistently lower memory at every moment.
These results show better resource usage, especially on the slower phone. They do not show faster overall test completion. CPU percentages can exceed 100% because they include work across multiple cores.
Flashlight report
iOS
A similar XCTest automation exercised opening and scrolling a large chat on an iPhone 14 Pro running iOS 26.6.1. Apple Instruments collected CPU, memory, hangs, and hitches while the test ran.
This setup did not capture FPS. Instead, the Hitches instrument measured delayed frames, and the Hangs instrument recorded brief unresponsiveness lasting more than 100 ms.
I extracted the following values from the supplied .trace file. It contains one recording per implementation. CPU and RAM averages cover each complete recorded window.
LegendList used approximately 102 MiB less RAM on average, with a 164 MiB lower peak. Average CPU usage was also lower.
The smoothness result is mixed. LegendList produced fewer hitches, but those hitches lasted longer on average, and their combined duration increased slightly. Both implementations recorded two brief hangs. We should describe this as lower CPU and memory usage with fewer, longer hitches, rather than an improvement in every responsiveness metric.
The recordings have different lengths and were stopped manually, so recording length is not a reliable measure of test completion speed. These results should also remain separate from the earlier five-run XCTest measurements.
Conclusion
These benchmarks support migrating to LegendList: it consistently reduces CPU and memory usage, while improving performance on slower devices and maintaining comparable FPS on faster hardware. The gains are especially valuable for large, complex lists such as
ReportActionsList.roryabraham commentedon Sep 1, 2026
Awesome, great work @chrispader! Let's roll it out 🎉
Were you able to do it without LegendList patches?
chrispader commentedon Sep 3, 2026
So far i didn't need any patches. I'm going to sort out any remaining issues and edge cases, but i don't think we're going to need to patch the library at all.
64 remaining items
melvin-bot commentedon Oct 29, 2026
@dmkt9
The solution for this issue has been 🚀 deployed to production 🚀 in version 9.5.25-2 and is now subject to a 7-day regression period 📆. Here is the list of pull requests that resolve this issue:
melvin-bot commentedon Oct 31, 2026
@dmkt9
The solution for this issue has been 🚀 deployed to production 🚀 in version 9.5.26-1 and is now subject to a 7-day regression period 📆. Here is the list of pull requests that resolve this issue: