React Native

How to Fix "VirtualizedLists Should Never Be Nested Inside Plain ScrollViews"

4 min read by DebuggedIt

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>
  );
}
Two competing scroll containers ScrollView (renders everything) ProfileHeader FlatList — tries to virtualize, but parent already renders everything Fix: use FlatList's ListHeaderComponent instead of wrapping it

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 shared ScrollView to 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.