| | |

YAML 04 📄 Mapping Sequences and Dictionaries

⏱️ Estimated read: 9 min | |

YAML represents structured data through three primitive structures: scalars, sequences, and mappings . A mapping is a set of key-value pairs—what other languages call a dictionary, hash, or object. A sequence is an ordered list of values—an array or list. The two compose freely: a mapping value can be a sequence, a sequence item can be a mapping, and either can nest inside the other to arbitrary depth.

This chapter covers the syntax for both structures in block style, the nesting patterns that combine them, and the shortcuts that reduce verbosity without changing meaning. It explains why indentation is the only structural signal, how the dash and colon separators work, and the merge key that lets one mapping inherit another’s entries. The sections that follow walk through sequences, mappings, their combination, and the reuse mechanisms.

Key point: Mappings use key: value pairs and sequences use - item entries; nesting is expressed by indentation alone, and every child must be indented more than its parent while siblings share identical indentation.


Why mappings and sequences exist

The structure problem. A configuration file is rarely a flat list of values. A Kubernetes manifest has a metadata mapping, a spec mapping, and inside spec a containers sequence of mappings. Without mappings and sequences that nest, every configuration would flatten into dotted keys like spec.containers.0.image, which is unreadable and error-prone. YAML’s block syntax mirrors the data’s own hierarchy: the indentation you see is the nesting the parser reads .

The ordering distinction. Mappings are unordered; the order of keys does not affect meaning, though most parsers preserve insertion order for readability . Sequences are ordered; the position of each item is part of the data. This distinction matters when converting between YAML and JSON or when writing code that iterates a mapping versus an array.

The merge reuse problem. Configuration files repeat the same defaults across multiple services. Without a reuse mechanism, every service block re-declares the same timeout and retry settings, and a change to the default requires editing every block. YAML’s merge key << inserts the entries of one mapping into another, so shared defaults live in one anchor and each service overrides only what differs .


a. Sequences: block and flow syntax

A block sequence places each item on its own line, prefixed with a dash and a space. The dash counts as indentation, which is why a sequence nested under a key can sit at the same column as the key’s value without extra spaces .

# Block sequence: one dash per item
environments:
  - development
  - staging
  - production

# Sequence of sequences: empty dash, then indented items
matrix:
  - - 1
    - 2
  - - 3
    - 4

# Flow sequence: inline brackets
roles: [admin, editor, viewer]

The space after the dash is mandatory. -item without a space is not a sequence entry; it is a plain scalar beginning with a hyphen. The same rule applies to the colon in mappings: key:value without a space after the colon is a single string, not a key-value pair .


b. Mappings: key-value pairs and nesting

A block mapping writes each key on its own line, followed by a colon and a space. The value can be a scalar, another mapping, or a sequence. Nested mappings are indented under their parent key.

# Flat mapping
database:
  host: db.example.com
  port: 5432

# Nested mapping: credentials is a child of database
database:
  host: db.example.com
  credentials:
    username: app_user
    password: secret

# Flow mapping: inline braces
point: { x: 1, y: 2 }

A mapping value can be a sequence. The sequence can start on the same line as the key or on the next line, indented. Both forms parse identically.

# Sequence on the next line
allowed_hosts:
  - localhost
  - example.com

# Flow sequence inline
allowed_hosts: [localhost, example.com]

c. Combining mappings and sequences

The most common real-world structure is a sequence of mappings: a list where each item is a dictionary. This is the shape of a Kubernetes containers list, a Docker Compose services block, and an Ansible task list.

# Sequence of mappings: each dash starts a new mapping
services:
  - name: web
    image: nginx:latest
    ports:
      - "80:80"
  - name: db
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: secret

The indentation rule is precise: the keys within one mapping must align with each other, and the dash of the next item must align with the dash of the first . A key indented under another key becomes its child; a key at the same indentation is its sibling.

The merge key << reuses a mapping’s entries. An anchor marks the source mapping; an alias references it; the merge key inserts its pairs into the target .

# Define defaults once with an anchor
defaults: &defaults
  timeout: 30
  retries: 3

# Merge defaults into each service; endpoint overrides nothing
service_a:
  <<: *defaults
  endpoint: /a

service_b:
  <<: *defaults
  endpoint: /b

# service_a and service_b both have timeout: 30 and retries: 3

Complete Example Session

# ============================================
# PART 1: SEQUENCE OF SCALARS
# ============================================
regions:
  - us-east-1
  - eu-west-1
  - ap-southeast-1

# ============================================
# PART 2: MAPPING OF SCALARS
# ============================================
server:
  host: 0.0.0.0
  port: 8080
  debug: false

# ============================================
# PART 3: MAPPING CONTAINING A SEQUENCE
# ============================================
firewall:
  allowed_ports:
    - 80
    - 443
    - 22

# ============================================
# PART 4: SEQUENCE OF MAPPINGS (THE COMMON SHAPE)
# ============================================
containers:
  - name: app
    image: myapp:1.0
    env:
      - name: NODE_ENV
        value: production
  - name: sidecar
    image: proxy:2.1

# ============================================
# PART 5: MERGE KEY FOR SHARED DEFAULTS
# ============================================
defaults: &defaults
  timeout: 30
  retries: 3

api:
  <<: *defaults
  endpoint: /api

worker:
  <<: *defaults
  endpoint: /worker
  timeout: 60   # override just this one

# ============================================
# PART 6: THE PARSED MENTAL MODEL
# ============================================
# containers: [
#   { name: "app", image: "myapp:1.0",
#     env: [ { name: "NODE_ENV", value: "production" } ] },
#   { name: "sidecar", image: "proxy:2.1" }
# ]
# api: { timeout: 30, retries: 3, endpoint: "/api" }
# worker: { timeout: 60, retries: 3, endpoint: "/worker" }

The parts covered scalar sequences, scalar mappings, a mapping containing a sequence, the sequence-of-mappings shape, merge key reuse with an override, and the parsed data model.


Quick Reference

Structural Syntax

StructureBlock SyntaxFlow Syntax
Sequence- item per line[item1, item2]
Mappingkey: value per line{key1: v1, key2: v2}
Nested sequenceDash at same column[[1, 2], [3, 4]]
Sequence of mappingsDash, then indented keys[{k: v}, {k: v}]

Nesting Rules

RuleDetail
Child indentationGreater than parent
Sibling alignmentIdentical column
Dash as indentCounts as structural indentation
Space after dashRequired (- item, not -item)
Space after colonRequired (key: value, not key:value)

Merge Key

ElementSyntaxPurpose
Anchor&nameMark a mapping for reuse
Alias*nameReference the anchored mapping
Merge<<: *nameInsert entries into current mapping
Overridekey: value after <<Replace merged value

Best Practices

✅ Do This:

# Align sibling keys exactly
server:
  host: localhost
  port: 8080                                                 # ✅

# Indent sequence items under their key
ports:
  - "80:80"
  - "443:443"                                                # ✅

# Use merge for shared defaults
defaults: &d
  timeout: 30
api: { <<: *d, endpoint: /api }                              # ✅

# Quote port mappings (colon trap)
ports:
  - "3000:3000"                                              # ✅

❌ Don’t Do This:

# Misaligned sibling
server:
  host: localhost
   port: 8080                                                # ❌

# Missing space after dash
items:
  -one                                                       # ❌ (scalar "-one")

# Missing space after colon
key:value                                                    # ❌ (single scalar)

# Unquoted colon in port mapping
ports:
  - 3000:3000                                                # ❌ (colon trap)

Common Pitfalls

PitfallWhy It HappensFix
Sequence items parsed as scalarsNo space after dash- item, not -item
Mapping key parsed as stringNo space after colonkey: value, not key:value
Key becomes child of anotherSibling indentation offAlign siblings at same column
Port mapping failsUnquoted colon in valueQuote as "3000:3000"
Merge does not applyAnchor and alias mismatchCheck &name and *name spelling
Sequence-of-mappings misalignedSecond dash not at first dash’s columnAlign all dashes in the sequence

Real-World Examples

1. Scalar sequence

tags: [yaml, config, data]

2. Scalar mapping

host: localhost
port: 8080

3. Mapping with sequence value

allowed_ips:
  - 10.0.0.1
  - 10.0.0.2

4. Sequence of mappings

users:
  - name: Ana
    role: admin
  - name: Ben
    role: viewer

5. Nested mapping

database:
  credentials:
    username: app

6. Merge key

base: &base
  retries: 3
service: { <<: *base, url: /svc }

7. Flow sequence in mapping

roles: [admin, editor]

8. Sequence containing sequence

matrix:
  - [1, 2]
  - [3, 4]

9. Quoted port mapping

ports:
  - "8080:80"

10. Kubernetes containers shape

containers:
  - name: app
    image: nginx
    ports:
      - containerPort: 80

Visual

Sequence vs Mapping

┌─────────────────────────────────────────────────────────┐
│  SEQUENCE (ordered list)                                │
│                                                         │
│  - apple                                                │
│  - banana                                               │
│  - carrot                                               │
│         │                                               │
│         ▼                                               │
│  ["apple", "banana", "carrot"]                          │
│  Position matters                                       │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│  MAPPING (key-value pairs)                              │
│                                                         │
│  name: Billy                                            │
│  age: 16                                                │
│         │                                               │
│         ▼                                               │
│  { name: "Billy", age: 16 }                             │
│  Order does not affect meaning                          │
└─────────────────────────────────────────────────────────┘

Sequence of Mappings

┌─────────────────────────────────────────────────────────┐
│  SEQUENCE OF MAPPINGS                                   │
│                                                         │
│  services:                                              │
│    - name: web          ◄── dash starts item 1          │
│      image: nginx           keys align under dash       │
│    - name: db           ◄── dash aligns with first      │
│      image: postgres        keys align under dash       │
│                                                         │
│  Parsed:                                                │
│  [                                                      │
│    { name: "web", image: "nginx" },                     │
│    { name: "db", image: "postgres" }                    │
│  ]                                                      │
└─────────────────────────────────────────────────────────┘

Merge Key Flow

┌─────────────────────────────────────────────────────────┐
│  MERGE KEY                                              │
│                                                         │
│  defaults: &defaults      ──┐                           │
│    timeout: 30              │                           │
│    retries: 3               │                           │
│                             │                           │
│  api:                       │                           │
│    <<: *defaults  ◄─────────┘ inserts both pairs        │
│    endpoint: /api                                       │
│                                                         │
│  Result:                                                │
│  api: { timeout: 30, retries: 3, endpoint: "/api" }    │
│                                                         │
│  Override after merge:                                  │
│  worker:                                                │
│    <<: *defaults                                        │
│    timeout: 60    ◄── replaces merged timeout           │
└─────────────────────────────────────────────────────────┘

Indentation as Structure

┌─────────────────────────────────────────────────────────┐
│  NESTING DEPTH                                          │
│                                                         │
│  root:              ◄── column 0                        │
│    child:           ◄── column 2 (child of root)        │
│      grandchild:    ◄── column 4 (child of child)       │
│    sibling:         ◄── column 2 (sibling of child)     │
│                                                         │
│  Same column = sibling                                  │
│  Deeper column = child                                  │
│  Shallower = closes current scope                       │
└─────────────────────────────────────────────────────────┘

Summary

ItemValue
Sequence syntax- item per line, space required
Mapping syntaxkey: value per line, space required
Flow sequence[item1, item2]
Flow mapping{key1: v1, key2: v2}
NestingIndentation only; children deeper than parent
Sequence of mappingsDash, then indented keys; align dashes
Merge key<<: *anchor inserts mapping entries
Merge overrideDeclare key: value after <<
Dash as indentCounts as structural indentation

Key takeaways:

  • Mappings and sequences are the two collection types. Mappings are key-value pairs (dictionaries); sequences are ordered lists. Every non-scalar YAML structure is one of these or a combination of them .
  • The dash and the colon require trailing spaces. -item is a scalar beginning with a hyphen; key:value is a single string. The space is the separator, not the punctuation alone .
  • Nesting is indentation, and alignment is meaning. A child is indented more than its parent; siblings share the same column. A one-space misalignment changes which node a key belongs to.
  • Sequence of mappings is the workhorse shape. Kubernetes containers, Docker Compose services, and Ansible tasks all use the pattern where each dash starts a mapping and the keys align under that dash .
  • The merge key reuses mappings without duplication. An anchor marks the source, an alias references it, and << inserts its pairs into the target. Overrides declared after the merge replace the inherited values .

Remember: YAML’s collection syntax is small: dash for sequence, colon for mapping, indentation for nesting. The failures come from the spaces—a missing space after a dash, a colon without a following space, a sibling one column out of alignment. When a file parses incorrectly, check the dash-space and colon-space first, then verify that siblings align and children are indented. The structure you see is the structure the parser reads; there is no other signal.

Was this helpful?


Stop using slow, ad-bloated tool sites! 🤮

🔎 Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)

⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free

🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!