Photo galleries, product catalogues, dashboards of stat cards — anything laid out in rows and columns of equal cells calls for a GridView. Flutter gives you a few constructors and two grid delegates that, between them, cover fixed-column grids, lazily-built infinite grids, and responsive grids that change their column count with the screen size. This tutorial builds each kind step by step, with paste-ready code.

The Complete Flutter Guide: Build Android, iOS and Web apps
Go from scratch to building industry-standard apps with Riverpod, Firebase, animations, REST APIs, and more.
Enrol nowEvery snippet below is paste-ready against current stable Flutter. GridView is the grid counterpart to ListView.builder and shares its scrolling model, covered in the scrolling and slivers guide — both pair naturally with this tutorial.
We'll start with the quick GridView.count, move to the efficient GridView.builder, control spacing and cell shape with the grid delegate, and finish with a responsive grid that adapts its columns to the screen.
If you'd rather watch a gallery grid built and made responsive in real time, the channel covers exactly that inside full projects.
GridView.count: the quick start
The fastest grid to write is GridView.count: you give it a fixed crossAxisCount — the number of columns — and a list of children.
GridView.count(
crossAxisCount: 2, // two columns
mainAxisSpacing: 12,
crossAxisSpacing: 12,
padding: const EdgeInsets.all(12),
children: [
for (final c in colours) ColoredBox(color: c),
],
)
This is perfect for a small, fixed set of items — a four-tile dashboard, a colour swatch picker. But it builds every child immediately, so for a long or unknown-length grid you want the lazy builder instead.
GridView.builder: the efficient default
For any grid that could be long, GridView.builder builds cells on demand as they scroll into view. You supply an itemCount, an itemBuilder, and a gridDelegate that describes the grid shape.
GridView.builder(
itemCount: products.length,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 12,
crossAxisSpacing: 12,
childAspectRatio: 0.75, // taller than wide, for a card + caption
),
itemBuilder: (context, index) => ProductCard(products[index]),
)
This is the grid you'll reach for most. The SliverGridDelegateWithFixedCrossAxisCount fixes the column count; childAspectRatio sets each cell's width-to-height ratio, which is the knob to turn when items look squashed or stretched.
Spacing and cell shape
Three delegate properties shape the grid: crossAxisSpacing (gap between columns), mainAxisSpacing (gap between rows), and childAspectRatio (cell proportions). They matter more than they sound — most "my grid looks wrong" problems are an aspect ratio away from fixed.
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
childAspectRatio: 1, // perfect squares
)
A childAspectRatio of 1 gives square cells; greater than 1 is wider than tall; less than 1 is taller than wide. Set it to match your content — a square photo grid uses 1, a card with a caption below uses something like 0.7.

Build galleries that adapt to any screen
The Complete Flutter Guide covers grids, responsive layout, and image performance from first principles through to shipped apps.
Enrol nowResponsive grids
A fixed crossAxisCount that looks right on a phone shows comically wide cells on a tablet. The fix is SliverGridDelegateWithMaxCrossAxisExtent: instead of a column count, you give it a maximum cell width and Flutter computes how many columns fit the current screen.
GridView.builder(
itemCount: photos.length,
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 180, // each cell at most 180px wide
mainAxisSpacing: 12,
crossAxisSpacing: 12,
childAspectRatio: 1,
),
itemBuilder: (context, index) => Image.network(photos[index]),
)
Now the same grid shows two columns on a narrow phone and five or six on a wide tablet, with no breakpoint logic from you. (GridView.extent is the shorthand constructor for this delegate.) For a deeper look at adapting whole screens, see the responsive UI guide; for the images themselves, the Image guide covers caching at display size, which matters in a busy grid.
Common mistakes
- Using GridView.count for a long grid. It builds every child up front; use
GridView.builderfor anything that could be long. - Squashed or stretched cells. Tune
childAspectRatioto match your content's shape. - Fixed crossAxisCount on every device. Use
maxCrossAxisExtentfor a grid that adapts to screen width. - GridView inside a Column without bounds. Wrap it in
Expanded, or setshrinkWrap: truefor a short, non-scrolling grid. - Full-resolution images in cells. Decode at display size with
cacheWidthto keep a photo grid smooth.
Frequently asked questions
What is the difference between GridView.count and GridView.builder in Flutter?
GridView.count builds all children eagerly with a fixed column count; GridView.builder builds lazily and scales to long grids. Prefer builder for anything that could be long.
How do I make a responsive grid in Flutter?
Use SliverGridDelegateWithMaxCrossAxisExtent (or GridView.extent) with a maxCrossAxisExtent; Flutter picks the column count for the screen.
What does childAspectRatio do in a Flutter GridView?
It sets each cell's width-to-height ratio — 1 for squares, >1 for wide cells, <1 for tall cells. It fixes squashed or stretched items.
How do I put a GridView inside a Column in Flutter?
Wrap it in Expanded for a scrollable grid, or set shrinkWrap: true with NeverScrollableScrollPhysics for a short, non-scrolling one.
Further reads
Keep going with the tutorials that pair with this guide:
- Flutter Development Guide 2026 — the full Flutter hub.
- Flutter ListView.builder — the single-column counterpart to GridView.
- Flutter Scrolling and Slivers — the scrolling model and SliverGrid.
- Responsive Flutter UI for All Screens — adapt whole layouts, not just grids.
- Flutter Image Widget — efficient images for photo grids.
Sources: Flutter documentation — GridView, GridView.builder, GridView.count, GridView.extent, SliverGridDelegateWithFixedCrossAxisCount, and SliverGridDelegateWithMaxCrossAxisExtent API references (docs.flutter.dev). Verified against current stable Flutter.