Bootstrap 5's Grid System: How Containers, Columns, and Gutters Actually Work
Bootstrap 5's grid is a 12-column flexbox system where containers set width strategy, breakpoint classes size columns mobile-first, and gutters belong on the row — here's a worked example plus the mistakes that silently break it.
14 Oct 2025, 13:40 UTC

The short answer
Bootstrap 5's grid is a 12-column flexbox system. You pick a container (fixed-width or fluid), wrap columns in a .row, and size each column with breakpoint-prefixed classes like .col-md-6. Spacing between columns comes from gutter utilities (.g-3, .gx-4) applied to the row — not from margins on the columns themselves. If you remember one rule, it's this: columns must be direct children of a row, and all horizontal spacing belongs on the row.
Containers: pick your width strategy first
Everything in the grid sits inside a container, and Bootstrap gives you three behaviors:
.container— a fixed max-width that steps up at each breakpoint (e.g., 720px atmd, 960px atlg). Content stays centered with breathing room on large screens..container-fluid— always 100% of the viewport width. Use this for dashboards or full-bleed layouts..container-md(or any breakpoint) — fluid below that breakpoint, fixed at and above it. Useful when mobile needs full width but desktop should be constrained.
Choosing the wrong container is the most common source of "why is my layout stretched on my monitor" complaints. Decide this before writing any column classes.
A worked example: three cards that reflow
Here is a complete, supported pattern for a card row that stacks on phones, shows two per row on tablets, and three per row on desktops:
<div class="container">
<div class="row g-3">
<div class="col-md-6 col-lg-4">Card 1</div>
<div class="col-md-6 col-lg-4">Card 2</div>
<div class="col-md-6 col-lg-4">Card 3</div>
</div>
</div>How to read the classes:
.col-md-6means "from themdbreakpoint (768px) upward, take 6 of 12 columns" — half the row. Belowmd, no width class applies, so each div becomes a full-width block and stacks vertically..col-lg-4overrides that atlg(992px) and up: 4 of 12 columns, one third of the row..g-3on the row sets a 1rem gutter (Bootstrap's spacing scale runs 0–5, where 3 = 1rem) both horizontally and vertically.
Classes are mobile-first: a class applies at its breakpoint and everything above unless a larger-breakpoint class overrides it. There is no xs infix — .col-6 applies from zero pixels up.
How the mechanism works under the hood
The row is a flex container with negative horizontal margins; each column has matching horizontal padding. That margin/padding pair is the gutter. The column's width comes from flex: 0 0 auto plus a percentage width (e.g., col-lg-4 computes to 33.333%). Because gutters are padding on the columns, the visible content boxes align flush with the container edges even though spacing exists between them.
This design has two practical consequences:
- Don't add your own horizontal margins to columns. You'll break the edge alignment the negative margins are compensating for. If you need more space, raise the gutter size (
.g-4,.g-5) or use padding utilities inside the column's content. - Don't wrap columns in extra divs. Flexbox only lays out direct children.
<div class="row"><div><div class="col-6">...</div></div></div>silently breaks the grid because the anonymous wrapper, not the column, becomes the flex item.
Column sizing options beyond fixed numbers
.col— equal-width auto-layout. Three.coldivs in a row each take one third, at every breakpoint..col-auto— shrink to content width. Handy for a sidebar sized by its contents, but if the content is wider than the remaining space it will overflow; pair it with.overflow-hiddenor amin-widthutility on the sibling column.- Nesting — put a new
.rowinside a column and you get a fresh 12-column context within that column. The nested row's gutters work the same way.
Per-axis gutters are available too: .gx-4 controls only horizontal spacing, .gy-2 only vertical. Use .gy-* when columns wrap onto multiple lines and you want consistent vertical rhythm without widening horizontal gaps.
Common mistakes and limits
- Writing
.col-xs-6. It doesn't exist. The smallest breakpoint has no infix; use.col-6. The invalid class fails silently, so the layout just stacks and you may not notice until you test on a phone. - Expecting gutters to add outer spacing. Gutters only space columns from each other; the row's outer edges stay flush with the container. If you want space between the grid and surrounding elements, add margin utilities (
.my-4) to the container or section. - Mixing grid with custom flex rules. Overriding
displayorflexon rows/columns fights Bootstrap's computed values. Prefer the built-in sizing classes or utility classes over custom CSS on grid elements. - Breakpoint assumptions. The defaults are sm 576px, md 768px, lg 992px, xl 1200px, xxl 1400px. These are customizable via Sass, so if you're working in a themed project, verify the actual values in the compiled CSS rather than assuming defaults.
How to verify your layout
Save the worked example in an HTML file with the Bootstrap 5 CSS linked, open it in a browser, and drag the viewport across 768px and 992px — you should see the stack → two-up → three-up transitions. In DevTools, select a column and check the computed width: at ≥992px it should be 33.3333% of the row, at 768–991px 50%. If the percentages are right but the visual layout is wrong, the problem is almost always a wrapper div or a custom margin — inspect the row's direct children to confirm the structure.
Note: breakpoint pixel values and gutter scale described here reflect Bootstrap 5 defaults; if you use a customized build, confirm against your compiled stylesheet.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.