Three widgets in Flutter set size, and they are easy to confuse: SizedBox pins an exact dimension, ConstrainedBox sets a range, and Container can do either as a side effect of being a do-everything box. Reaching for the wrong one means heavier widget trees, layouts that don't react to constraints the way you expect, and the occasional silent "my SizedBox did nothing" surprise. This guide draws the line between all three, 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. Sizing only makes sense in the context of Flutter's constraints model, so if "constraints go down, sizes go up" isn't second nature yet, the Layout Widgets guide is the prerequisite this post builds on.
We'll cover what SizedBox does and its shrink/expand shortcuts, how ConstrainedBox and BoxConstraints set a range instead of a point, when Container earns its place, FractionallySizedBox for proportional sizing, and a clear rule for picking one every time.
If you learn faster by watching code take shape, the channel builds these sizing patterns inside real screens where the choice between the three actually changes the result.
SizedBox: a single, exact size
SizedBox forces its child to a specific width and/or height. Either dimension can be omitted, in which case that axis is left to the parent's constraints.
SizedBox(
width: 200,
height: 48,
child: ElevatedButton(onPressed: () {}, child: const Text('Save')),
)
Its second job is the one you'll use even more often: empty space. A SizedBox with a height and no child is the standard, allocation-free way to put a gap between widgets in a Column or Row.
Column(
children: const [
Text('Title'),
SizedBox(height: 12), // a clean 12px gap
Text('Subtitle'),
],
)
Two named constructors round it out. SizedBox.shrink() is a zero-by-zero box — handy as a "render nothing" placeholder in a conditional. SizedBox.expand() sets both dimensions to infinity so the box fills whatever space the parent permits.
const SizedBox.shrink() // 0 x 0 — an empty placeholder
const SizedBox.expand() // fills all available space
ConstrainedBox: a range, not a point
Where SizedBox dictates one size, ConstrainedBox sets bounds and lets the child choose within them. You pass it a BoxConstraints describing minimum and maximum width and height.
ConstrainedBox(
constraints: const BoxConstraints(
minWidth: 120,
maxWidth: 320,
minHeight: 48,
),
child: Text('I grow with my text, but never past 320px wide'),
)
This is the right tool for "at least this big, at most that big" — a button that should never be narrower than 120 logical pixels but is free to grow with a long label, or a card that caps its width on a wide tablet so the line length stays readable. The child sizes itself naturally and the constraints simply clamp the result.
BoxConstraints also has expressive named constructors: BoxConstraints.tightFor(width: 100) pins one axis while leaving the other free, BoxConstraints.loose(size) allows zero up to a maximum, and BoxConstraints.expand() demands the full available space. Most of the time the plain constructor with the min/max fields you need is the clearest.

Understand constraints once, debug layouts forever
The Complete Flutter Guide teaches Flutter's constraint model so sizing stops being trial and error.
Enrol nowContainer: sizing plus everything else
Container can set a width and height too, which is why people reach for it out of habit. But Container is a convenience widget that internally composes several others — alignment, padding, decoration, constraints, and sizing — so using it purely to set a dimension wraps your child in machinery it doesn't need.
// Overkill if all you want is a size:
Container(width: 200, height: 48, child: child)
// Lighter, and can be const:
const SizedBox(width: 200, height: 48, child: child)
The moment you add a decoration, the calculus flips: if the box needs a background colour, border, gradient, or rounded corners and a size, Container is exactly right — it would be silly to nest a DecoratedBox inside a SizedBox by hand. The full breakdown of what Container bundles lives in the Container widget guide.
FractionallySizedBox: proportional sizing
When you want a child to take a fraction of the space its parent offers — half the width, a third of the height — FractionallySizedBox expresses that directly with widthFactor and heightFactor between 0 and 1.
FractionallySizedBox(
widthFactor: 0.6, // 60% of the available width
child: ElevatedButton(onPressed: () {}, child: const Text('Continue')),
)
This reacts to local constraints, which is usually what you want — a button that is 60% of its row will adapt on every screen size without you reading MediaQuery. Reach for MediaQuery.of(context).size only when you genuinely need to size against the whole device rather than the immediate parent.
Why a SizedBox sometimes seems to do nothing
A common surprise: you wrap a widget in SizedBox(width: 50, height: 50) and the child ignores it. This happens because some widgets impose their own constraints. For example, an Image with a fixed source size, or a child already given tight constraints by a parent Expanded, can override what the SizedBox asks for. SizedBox sets the constraints it passes down; if a stronger constraint sits above or the child is inflexible, the visible size won't match. When that happens, check the chain of parents — the constraint actually in force is the one nearest the child that is tight.
Choosing the right widget
- Use
SizedBoxfor an exact width/height, or as the cleanest way to add empty space between widgets. - Use
ConstrainedBoxwhen you need a minimum or maximum but want the child to size itself within that range. - Use
Containerwhen you need a size and a decoration, padding, margin, or alignment in one widget. - Use
FractionallySizedBoxfor a size expressed as a fraction of the available space.
Common mistakes
- Using Container just to set a size. Prefer
SizedBox— it is lighter and can beconst. - Expecting SizedBox to win against tight parent constraints. The nearest tight constraint to the child decides; a SizedBox can't override an
Expandedabove it. - Reaching for ConstrainedBox when you mean an exact size. If min equals max you want a SizedBox; constraints are for ranges.
- Hand-rolling percentage maths with MediaQuery.
FractionallySizedBoxis usually cleaner and reacts to local constraints, not just device size. - Adding empty Containers for spacing. A childless
SizedBoxcommunicates intent better and allocates nothing extra.
Frequently asked questions
What is the difference between SizedBox and ConstrainedBox in Flutter?
SizedBox sets one exact size; ConstrainedBox sets a range via BoxConstraints (min/max width and height) and lets the child choose within it.
Should I use SizedBox or Container in Flutter?
Use SizedBox for size or spacing alone — it is lighter and can be const. Use Container when you also need a decoration, padding, margin, or alignment.
What does SizedBox.expand do in Flutter?
It sets width and height to infinity so the box fills the space the parent allows. SizedBox.shrink is its zero-size counterpart.
How do I size a widget as a percentage of the screen in Flutter?
Use FractionallySizedBox with widthFactor/heightFactor for a fraction of the parent's space, or read MediaQuery.of(context).size to size against the whole device.
Further reads
Keep going with the tutorials that pair with this guide:
- Flutter Development Guide 2026 — the full Flutter hub.
- Flutter Layout Widgets: The Complete Guide — the constraints model these widgets rely on.
- Flutter Container Widget Explained — what Container bundles, and when sizing belongs in it.
- Flutter Expanded vs Flexible vs Spacer — flexible sizing along a main axis, the counterpart to fixed sizing.
- Flutter Padding, Margin, and EdgeInsets — spacing around a sized box.
- Flutter Image Widget — give an image a known size for BoxFit to work against.
Sources: Flutter documentation — SizedBox, ConstrainedBox, BoxConstraints, Container, and FractionallySizedBox API references, plus the Understanding constraints article (docs.flutter.dev). Verified against current stable Flutter.