Flutter ListView vs GridView: Choosing and Building Scrollable Layouts

ListView and GridView are both scrollable layout widgets built on the same underlying machinery, and share most of their constructors and performance characteristics. The difference is purely about arrangement: one column versus a grid.

ListView: One Item After Another

ListView.builder(
  itemCount: messages.length,
  itemBuilder: (context, index) {
    return ListTile(title: Text(messages[index].text));
  },
)

Use ListView.builder (not the plain ListView(children: [...]) constructor) for anything beyond a handful of items — it only builds the widgets currently visible on screen, rather than every item up front, which matters a lot for a list with hundreds or thousands of entries.

GridView: A Fixed Number of Columns

GridView.builder(
  gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
    crossAxisCount: 2,
    mainAxisSpacing: 8,
    crossAxisSpacing: 8,
  ),
  itemCount: products.length,
  itemBuilder: (context, index) {
    return ProductCard(product: products[index]);
  },
)

The gridDelegate is what makes GridView different from ListView — it decides how items are arranged into rows and columns. SliverGridDelegateWithFixedCrossAxisCount is the most common choice: a fixed number of columns, with row heights determined automatically.

Sizing Columns by Width Instead of Count

For a responsive grid where the column count should adapt to screen width rather than being fixed, use SliverGridDelegateWithMaxCrossAxisExtent instead — you specify a maximum item width, and Flutter fits as many columns as will comfortably fit:

gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
  maxCrossAxisExtent: 200,
  mainAxisSpacing: 8,
  crossAxisSpacing: 8,
),

Choosing Between Them

The decision is almost always about content shape, not performance — both are equally efficient when built with their .builder constructors:

  • ListView — content that reads naturally top to bottom: a chat, a feed, settings, search results.
  • GridView — content that’s visually browsed rather than read in order: a photo gallery, a product catalog, an icon picker.

For something in between — a list where certain rows should span multiple columns — look at SliverGrid with a custom delegate, or consider whether the layout is really trying to be a Wrap instead.