Every field type so far stores exactly one value. A Repeater field stores a whole list of them — rows an editor can add, remove, and reorder freely, each containing the same set of sub-fields.
A "Features" repeater on a product, for example, might have two sub-fields per row: feature_title and feature_description. An editor sees an "Add Row" button and can end up with three rows, ten rows, or zero — the template code stays exactly the same regardless of how many.
<?php if ( have_rows( 'features' ) ) : ?>
<ul>
<?php while ( have_rows( 'features' ) ) : the_row(); ?>
<li>
<strong><?php the_sub_field( 'feature_title' ); ?></strong>
<?php the_sub_field( 'feature_description' ); ?>
</li>
<?php endwhile; ?>
</ul>
<?php endif; ?>The pattern deliberately echoes the Loop from earlier: have_rows() checks for another row, the_row() advances to it, and the_sub_field() / get_sub_field() read a sub-field from the current row — the same the_/get_ split as regular fields, just scoped to one row at a time.
A Group field looks similar but solves a different problem — it bundles a fixed, non-repeating set of related sub-fields under one field, mostly to keep a large field group organized rather than to repeat anything:
<?php $address = get_field( 'company_address' ); ?>
<p><?php echo esc_html( $address['street'] ); ?>, <?php echo esc_html( $address['city'] ); ?></p>get_field() on a Group returns one array with every sub-field as a key — no looping needed, since there's always exactly one of it.
Keep repeaters shallow
Repeaters can technically be nested inside each other, but it's worth resisting past one level. A repeater-inside-a-repeater is a genuinely awkward editing experience for whoever fills it in — if the data needs that much structure, a second custom post type (linked with a Post Object or Relationship field) is usually the better fit.
With structured, repeatable content covered, the next lesson looks at data that doesn't belong to any single post at all — site-wide settings, using an SCF options page.