How to Fix "VirtualizedLists Should Never Be Nested Inside Plain ScrollViews"
Quick answer
Your app runs fine but logs a persistent warning about VirtualizedLists nested inside a plain ScrollView, and scroll performance on that screen may be...
Your app runs fine but logs a persistent warning about VirtualizedLists nested inside a plain ScrollView, and scroll performance on that screen may be noticeably worse than expected. This warning points at a structural layout issue — a FlatList or SectionList placed inside a ScrollView defeats the performance optimizations those list components are specifically built to provide.
The Problem
The app works, but the console shows a persistent yellow-box warning:
VirtualizedLists should never be nested inside plain ScrollViews with the same
orientation because it can break windowing and other functionality - use another
VirtualizedList-backed container instead.
This typically comes from a layout structure like this:
function ProfileScreen() {
return (
<ScrollView>
<ProfileHeader />
<FlatList
data={posts}
renderItem={({item}) => <PostCard post={item} />}
/>
</ScrollView>
);
}
Why It Happens
FlatList and SectionList are built on VirtualizedList, which only renders items currently visible (plus a small buffer) rather than every item in the data set at once — this is the core performance optimization that lets these components handle thousands of items smoothly. That optimization depends on the list controlling its own scroll viewport. When you nest one inside a plain ScrollView with the same scroll orientation, the outer ScrollView forces the inner list to measure and lay out its full content anyway (since the outer container needs to know the total scrollable height), which defeats windowing entirely — you end up paying the full rendering cost of every item regardless of the FlatList's virtualization logic. This typically happens when:
- A screen has some fixed header content followed by a scrollable list, and the natural-seeming approach was wrapping everything in one outer
ScrollView. - Multiple
FlatLists appear on the same screen, and they were wrapped in a sharedScrollViewto make the whole screen scroll together. - A component library or a copied code pattern nested a list inside a scroll container without the author realizing the performance implication.
The Fix
For the common case of fixed header content above a list, use the FlatList's own ListHeaderComponent prop instead of wrapping it in an outer ScrollView — this keeps everything within a single, correctly virtualized scroll container:
function ProfileScreen() {
return (
<FlatList
data={posts}
renderItem={({item}) => <PostCard post={item} />}
ListHeaderComponent={<ProfileHeader />}
/>
);
}
If you also need footer content after the list, there's an equivalent prop for that:
<FlatList
data={posts}
renderItem={({item}) => <PostCard post={item} />}
ListHeaderComponent={<ProfileHeader />}
ListFooterComponent={<LoadMoreButton />}
/>
For multiple distinct lists on one screen, SectionList is specifically designed for this — it renders multiple grouped sections, each with its own header, all within a single virtualized scroll container instead of nesting separate lists:
<SectionList
sections={[
{title: 'Recent Posts', data: recentPosts},
{title: 'Popular Posts', data: popularPosts},
]}
renderItem={({item}) => <PostCard post={item} />}
renderSectionHeader={({section}) => <SectionHeader title={section.title} />}
/>
If your layout genuinely needs a small, fixed-size list nested within a larger scrollable page (for example, a short horizontal carousel inside an otherwise vertically scrolling screen), the warning doesn't apply the same way when the nested list's scroll orientation differs from the parent's — a horizontal FlatList inside a vertical ScrollView is a legitimate, supported pattern:
<ScrollView>
<ProfileHeader />
<FlatList
horizontal
data={featuredItems}
renderItem={({item}) => <FeaturedCard item={item} />}
/>
</ScrollView>
Still Not Working?
If restructuring around ListHeaderComponent or SectionList genuinely doesn't fit your layout — for example, a complex screen with several independently-sized, unrelated lists mixed with other content — set nestedScrollEnabled as a targeted workaround rather than a proper fix, while accepting the associated performance trade-off documented in React Native's own warning:
<FlatList
data={posts}
renderItem={({item}) => <PostCard post={item} />}
nestedScrollEnabled={true}
/>
This suppresses the specific scroll-gesture conflicts on Android without addressing the underlying virtualization performance cost, so it's best treated as a stopgap while you plan a proper restructure using the patterns above, rather than a permanent solution for screens rendering large lists.