Architecture & Performance· 5 min read

FlatList vs FlashList vs LegendList: Lists That Don't Stutter

FlatList vs FlashList v2 vs LegendList in 2026: how each renders long lists, when to use which, and the row-level fixes that keep lists smooth.

By

Full-Stack, Mobile & AI Engineer

Lists are where React Native apps most often feel slow. Feeds, chats, catalogs and search results are the screens people scroll most, and every blank flash, dropped frame or jump when an image loads is noticed. Most of the time, React Native FlatList performance problems (and list problems generally) have an unexotic fix: the right list component plus lighter rows.

In 2026 there are three main options for long lists: React Native's built-in FlatList, Shopify's FlashList (now version 2, rebuilt for the New Architecture) and LegendList. This guide compares them, explains when each wins, and lists the row-level fixes that matter regardless of which you choose.

Key takeaways

  • ScrollView with .map() is only for short lists; it renders every item up front.
  • FlatList virtualises: it renders a window of items around the viewport, and it's fine for moderate lists with simple rows.
  • FlashList recycles views instead of creating new ones, which is faster for long, complex lists. Version 2 requires the New Architecture and no longer needs size estimates.
  • LegendList is a fast JavaScript-based list with features that suit chats and dynamic content, such as keeping scroll at the end.
  • Row weight matters more than the component: light rows, sized images and stable keys fix most scrolling problems.

The four options

ScrollView + mapFlatListFlashList v2LegendList
How it worksRenders everythingVirtualised window of itemsRecycles cells as you scrollVirtualised, with optional recycling
Built inYesYesNo (Shopify)No (Legend)
Long listsPoorGood with tuningExcellentExcellent
Size estimates neededNoOptional getItemLayoutNo (v2 measures automatically)No
ArchitectureAnyAnyNew Architecture onlyAny
Good forA handful of itemsModerate lists, simple rowsLarge feeds, catalogs, complex rowsChats, dynamic heights, scroll-to-end

ScrollView with map() vs FlatList: the common question

items.map() inside a ScrollView creates every row immediately. With 20 items that's fine. With 2,000 it's slow to open and heavy on memory. FlatList renders only what's near the screen, adding and removing rows as you scroll. If a list can grow beyond a screen or two, use a list component.

FlatList: fine, with tuning

FlatList is the built-in choice and works well for many apps. If it struggles:

  • Provide getItemLayout when rows have a fixed height, so it can skip measuring.
  • Tune initialNumToRender, maxToRenderPerBatch and windowSize to balance blank areas against work.
  • Memoise rows (React.memo) and pass stable callbacks.

When tuning stops helping, switch components rather than adding more tuning.

FlashList v2: the default for big lists

FlashList reuses ("recycles") the native views of rows that scroll off screen for new rows coming in, which avoids creating and destroying views constantly. Version 2 was a ground-up rewrite for the New Architecture:

  • No estimatedItemSize needed; sizes are handled automatically.
  • maintainVisibleContentPosition is on by default, which helps lists that load content above the viewport.
  • Masonry layouts are a prop rather than a separate component.

For heterogeneous rows (posts, ads and headers in one feed), give FlashList a getItemType so it recycles views between rows of the same type.

LegendList: strong for chats and dynamic content

LegendList is a high-performance list written in JavaScript, with features aimed at the hard cases: lists that should stay pinned to the bottom (chats), items whose heights change after loading, and smooth scroll-to-index. It's a good fit for messaging screens and other content that grows at the end.

Row-level fixes that matter more than the component

  1. Keep rows light. Fewer nested views, no heavy computation during render, no inline formatting of large data.
  2. Memoise rows and avoid passing new objects or functions as props on every render.
  3. Size images correctly and use a caching image component, with placeholders so rows don't jump.
  4. Use stable keys from your data, never array indexes for lists that change.
  5. Paginate. Load 20 to 50 items at a time and fetch more near the end.
  6. Avoid expensive effects in rows, such as subscriptions per row or layout measurements on every render.
From the field: Feeds and chat are the screens where list performance is most visible. I've scaled real-time chat and collaboration to 100K+ concurrent users with Socket.IO and Redis, and built Spoxio's athlete feeds with video highlights. In both kinds of screen, the biggest gains come from lighter rows and correctly sized media, with the list component as the multiplier.

Chat and other bottom-anchored lists

Chat screens are a special case: new content arrives at the bottom, older messages load at the top, and the view must stay pinned to the latest message without jumping. The traditional trick is an inverted list, which flips the list so index 0 sits at the bottom. It works, but it complicates accessibility and some gestures.

Modern options handle this more directly. LegendList can keep the scroll position at the end as items are added and align short lists to the bottom, and FlashList v2's default maintainVisibleContentPosition keeps the visible messages steady when older ones are inserted above. Whichever you choose, test with long messages, images that load late, the keyboard opening and closing, and a slow network, because chat screens hit every edge case at once.

How to measure list performance

  • Scroll the real list on a mid-range Android phone in a release build, with realistic data (long text, slow images, many items).
  • Watch the performance monitor for JavaScript frame drops while scrolling.
  • Look for blank areas during fast scrolls, a sign that rows render too slowly.
  • Profile row renders with the React profiler to find components that re-render unnecessarily.

FAQ

Is FlashList better than FlatList?

For long lists with complex rows, usually yes, because FlashList recycles views instead of creating new ones. Version 2 also removes the need for size estimates. For short or simple lists, FlatList is perfectly adequate and has no extra dependency.

Does FlashList v2 work on the old architecture?

No. FlashList v2 is built for the New Architecture only. Apps still on the legacy architecture need FlashList v1, and should plan a New Architecture migration to use current versions.

What is LegendList?

LegendList is a high-performance list component for React Native, designed as an alternative to FlatList and FlashList. It handles dynamic item heights and scroll-to-end behaviour well, which makes it popular for chat screens and growing content.

Why does my React Native list show blank spaces when scrolling fast?

Rows are rendering more slowly than you're scrolling. Make rows lighter, memoise them, size images properly, and consider FlashList or LegendList. For FlatList, increasing windowSize reduces blanks at the cost of more memory.

Next steps

If a key list in your app stutters, I can profile it on real devices and fix it, usually with lighter rows and the right list component. Get in touch, or see how I work as a React Native developer.

Sources

Bhuwanesh Sisodia

Bhuwanesh Sisodia

Full-Stack, Mobile & AI Engineer

Bhuwanesh Sisodia is a Full-Stack, Mobile & AI Engineer based in Mumbai, with 7+ years of experience and 50+ apps shipped to the App Store and Google Play. He works independently with startups and product teams worldwide.

About meGitHubLinkedInX

Related