# Lists and Nesting

Course: [Markdown](https://www.devtutorials.ai/learn/markdown) · Section: Markdown Fundamentals
Source: https://www.devtutorials.ai/learn/markdown/fundamentals/lists-and-nesting

> Write bullet, numbered and task lists that stay together. Repair a setup guide whose nested list collapsed, learn the indent rule, keep notes and code inside a step, and pick the list type an AI agent will read correctly.

## The Setup Guide That Collapsed

Asha writes a setup guide for the order-support app. She wants two steps, with two things to install under the first step. In her editor, it looks right:

```md runnable title="A setup guide that went flat"
1. Install the tools
 - Node 20
 - npm
2. Start the app
```

Look at the Rendered tab. "Node 20" and "npm" are not inside step 1. They became a separate bullet list between the steps. Open the HTML tab: there are three lists, not one. Step 2 ended up in a list of its own.

The cause is one missing space. In this lesson, you will learn exactly how much to indent, and the other rules that keep lists together.

**In simple words:** a list item belongs inside another item only when it lines up under that item's text.

## TL;DR

- A **bullet list** uses `-`, `*` or `+` and a space at the start of each line. Pick `-` and use it everywhere.
- A **numbered list** uses a number, a full stop and a space: `1. `. The first number sets where counting starts.
- To put a list inside a list, indent the inner items so they line up with the text of the outer item. That is 2 spaces under `- ` and 3 spaces under `1. `.
- Anything that is not indented ends the list.
- `- [ ]` and `- [x]` make a **task list** on GitHub.

## A Real-World Example

Think about a recipe.

The ingredients are a list. The order does not matter: you can fetch the eggs before the flour. The steps are a numbered list. The order matters: you cannot bake before you mix.

Some steps have small parts. "Prepare the pan" might have "grease it" and "line it with paper" written under it, a little to the right. That indent tells you they belong to that step.

Markdown lists work the same way. Bullets for things in any order. Numbers for things in a fixed order. An indent for parts that belong to one item.

## What You Will Learn

In this lesson, you will learn:

1. How to write bullet lists and numbered lists.
2. How the first number sets the count.
3. How far to indent a list inside a list.
4. How to keep text and code inside a list item.
5. How to write a task list.
6. Which list to use when an AI agent reads it.

## Cheat Sheet

```md runnable title="Every kind of list"
Bullets:

- Refunds
- Shipping
- Returns

Numbers:

1. Open the order
2. Check the receipt
3. Approve the refund

A list inside a list:

- Install the tools
  - Node 20
  - npm
- Start the app

A task list:

- [x] Fix refund rounding
- [ ] Add order search
```

Change the text, the marks and the spaces on the left. Watch how the right side changes.

## Bullet Lists

### Three Marks, One Result

A **bullet list** is a list where the order does not matter. Start each line with `-`, `*` or `+`, then a space.

```md runnable title="Three marks, three lists"
- Refunds
- Shipping

* Refunds
* Shipping

+ Refunds
+ Shipping
```

All three look the same on the page. Open the HTML tab: each one is a `ul`, which stands for unordered list. Each item is an `li`, a list item.

### Do Not Mix the Marks

There is a catch. If you change the mark in the middle of a list, Markdown starts a **new** list.

```md runnable title="One list, or three?"
- Refunds
* Shipping
+ Returns
```

This looks like one list with three items. Open the HTML tab. It is three separate lists with one item each. On the page, the gaps between them can look odd.

Pick one mark and use it in every file. Most teams use `-`.

The space after the mark matters. `-Refunds` with no space is not a list item. It is just text that starts with a dash.

## Numbered Lists

### Numbers and the First Number

A **numbered list** is a list where the order matters. Start each line with a number, a full stop and a space. A closing bracket works too: `1)`.

```md runnable title="The first number sets the count"
1. Open the order
1. Check the receipt
1. Approve the refund

A list that starts at 3:

3. Third step
4. Fourth step
```

The first list uses `1.` on every line, but the page shows 1, 2, 3. Markdown counts for you. Only the **first** number matters. The second list starts at 3, because its first number is 3.

Many people write `1.` on every line on purpose. Then you can add or remove a step without renumbering the rest. Open the HTML tab: a numbered list is an `ol`, an ordered list.

### When a Number Is Not a List

A line that starts with a number and a full stop becomes a list item, even when you did not mean it.

```md runnable title="A year that became a list"
2023. A great year for the team.

2023\. A great year for the team.
```

The first line turned into a list that starts at 2023. To stop that, put a backslash before the full stop, like the second line. The backslash tells Markdown "this is just a full stop".

## A List Inside a List

### The Indent Rule

A **nested list** is a list inside a list item. To nest an item, indent it so it lines up with the **text** of the item above. Not with the mark — with the text.

- Under `- Install`, the text starts 2 characters in. So indent the inner items by 2 spaces.
- Under `1. Install`, the text starts 3 characters in. So indent the inner items by 3 spaces.

```md runnable title="Line up with the text"
- Install the tools
  - Node 20
  - npm
- Start the app

1. Install the tools
   - Node 20
   - npm
2. Start the app
```

Both lists nest correctly. Open the HTML tab: the inner `ul` sits **inside** the first `li`.

Now go back to the box at the top of the lesson. Add two more spaces in front of `- Node 20` and `- npm`, so each has three. The guide joins up into one list.

Different apps handle the wrong indent in different ways. Some guess what you meant. CommonMark and GitHub do not. Line up with the text, and the list works everywhere.

### How Deep to Go

You can nest a list inside a nested list. Each level indents again. But two levels is usually enough. Deeper lists are hard to read, both as raw text and on the page.

If you need three levels, the content probably wants headings instead.

## Text and Code Inside a List Item

### Anything Not Indented Ends the List

A list ends at the first line that is not part of it. A paragraph with no indent breaks the list in two.

```md runnable title="A note that broke the numbering"
1. Install the tools

Do this before anything else.

2. Start the app
```

The note is not part of step 1, so the list ended there. Step 2 starts a new list, and its number came from the `2.` you typed. If you had typed `1.` on every line, the page would show "1" twice.

To keep the note inside step 1, indent it to line up with the step's text, 3 spaces:

```md runnable title="The note inside the step"
1. Install the tools

   Do this before anything else.

2. Start the app
```

Now there is one list with two steps, and the note belongs to step 1.

### Code Inside a Step

Setup guides often have a command inside a step. The same rule applies: indent the whole code block to line up with the step's text. You will learn about code blocks in a later lesson. For now, just look at the indent.

````md runnable title="A command inside a step"
1. Install the packages:

   ```bash
   npm install
   ```

2. Start the app:

   ```bash
   npm start
   ```
````

Each command sits inside its step. Delete the three spaces in front of the first code block and watch the list break in two.

### Tight and Loose Lists

You may notice that some lists have more space between items. That is because of blank lines.

- A list with no blank lines between items is **tight**. Items sit close together.
- A list with a blank line between items is **loose**. Each item is wrapped in a paragraph, so it gets more space.

Both are fine. Just do not mix them in one list, or the spacing looks uneven.

## Task Lists

A **task list** is a list of things to do, with a checkbox for each. Write `[ ]` for an open task and `[x]` for a done task, right after the bullet.

```md runnable title="A release checklist"
- [x] Fix refund rounding
- [x] Add order search
- [ ] Update the help centre
- [ ] Tell the support team
```

Now switch the box to **CommonMark**. The checkboxes are gone, and the page shows `[ ]` and `[x]` as text. Task lists are part of GitHub Flavored Markdown, not CommonMark. You will learn more about this difference in the Markdown Flavors lesson.

On GitHub, the boxes in an issue or a pull request can be ticked by clicking them. In a normal `.md` file, they are just a picture of the state you typed.

## Lists and AI Agents

AI agents read lists in the same way people do, so the type of list carries meaning.

| Use | When | Example |
|---|---|---|
| Numbered list | the order matters | setup steps, a release process |
| Bullet list | the order does not matter | project rules, features, team members |
| Nested list | an item has small parts | a step with two things to install |
| Task list | items will be done and ticked off | a checklist in a spec |

If your steps are bullets, an agent may run them in any order. If your rules are numbered, an agent may think rule 1 is more important than rule 5. Choose the list type that says what you mean.

## Where Lists Are Used

- **README files:** install steps as a numbered list, features as bullets.
- **Release notes:** one bullet per change.
- **Pull requests and issues:** task lists for what is left to do.
- **AI agent files:** a bullet list of rules, a numbered list of commands to run in order.
- **Specs:** a task list of acceptance checks.

## Common mistakes

| Symptom | Cause | Fix |
|---|---|---|
| The inner items show as a separate list | They are not indented enough to line up with the text above | Indent 2 spaces under `- `, 3 spaces under `1. ` |
| One list shows as several lists | The bullet mark changes partway through | Use the same mark on every item |
| The numbers restart, or a step shows "1" twice | An unindented paragraph ended the list | Indent the paragraph so it belongs to the step |
| A code block breaks the list | The fence is not indented to the step's text | Indent the whole code block |
| A sentence starting with a year became a list | `2023.` at the start of a line looks like a list number | Write `2023\.` |
| `[ ]` shows as text, not a checkbox | The renderer does not support GFM task lists | Use a GitHub-style renderer, or write "To do:" in words |
| Some items have bigger gaps than others | Blank lines between some items, not others | Use blank lines between all items, or none |

## Quick Check

## Exercises

## What to Remember

- Bullets (`-`) are for things in any order. Numbers (`1.`) are for steps in a fixed order.
- Use one bullet mark everywhere. A new mark starts a new list.
- Only the first number counts. Writing `1.` on every line is fine.
- To nest, line up with the text above: 2 spaces under `- `, 3 spaces under `1. `.
- Indent notes and code that belong to a step. Anything not indented ends the list.
- `- [ ]` and `- [x]` make a task list on GitHub.

## Further Reading

- [CommonMark: list items](https://spec.commonmark.org/0.31.2/#list-items): the exact indent rules.
- [GitHub Flavored Markdown: task list items](https://github.github.com/gfm/#task-list-items-extension-): how checkboxes work.
- [GitHub Docs: lists](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#lists): lists and nested lists on GitHub.

Next: **Links and Images**, where you link to other files and headings, add pictures with good alt text, and fix the broken links in the project's docs.
