Skip to main content

Markdown Lists

Bullet, numbered, and nested lists in Markdown: the exact indentation a nested item needs, how numbering really works, and why a list breaks or restarts.

Short answer

Start each line with - for a bullet or 1. for a number. To nest an item, indent it so its marker lines up with the parent's text: 2 spaces under a bullet, 3 under a number. Only the first number counts, so 1. on every line still renders 1, 2, 3. Leave a blank line before the list and after it.

Bullet Lists

Start each line with a hyphen, asterisk, or plus sign followed by a space. All three produce the same bullets.

Hyphen bullets
- First item
- Second item
- Third item
Preview
  • First item
  • Second item
  • Third item
Switching markers starts a new list
- Hyphen item
- Hyphen item
* Asterisk item
+ Plus item
Preview
  • Hyphen item
  • Hyphen item
  • Asterisk item
  • Plus item

In CommonMark and GitHub this is three separate lists, not one: changing from - to * or + ends the list. Pick one marker and stick with it.

Numbered Lists

Use a number, a period, and a space. The first number sets where the list starts. Every number after it is ignored, and the renderer counts up on its own.

Numbered list
1. First step
2. Second step
3. Third step
Preview
  1. First step
  2. Second step
  3. Third step
Start at any number
3. Third step
4. Fourth step
5. Fifth step
Preview
  1. Third step
  2. Fourth step
  3. Fifth step

Renders as <ol start="3">. Any number up to 9 digits works, including 0. If the list follows a paragraph, it needs a blank line above it, because only a list starting at 1 can interrupt a paragraph.

Lazy numbering
1. First step
1. Second step
1. Third step
Preview
  1. First step
  2. Second step
  3. Third step

Still renders 1, 2, 3. Handy when you reorder steps often; explicit numbers read better in the raw file.

Parenthesis delimiter
1) First step
2) Second step
Preview
  1. First step
  2. Second step

1) works the same as 1. in CommonMark and GitHub. Mixing the two in one list starts a new list at the switch.

Nested Lists

A nested item belongs to the item above it when it is indented at least as far as that item's text. CommonMark calls this the content column: the width of the marker plus the space after it. GitHub's own docs give the same rule: line the nested marker up under the first character of the parent's text.

Parent lineText starts at columnChild indent that nests
- Parent22 to 5 spaces
1. Parent33 to 6 spaces
10. Parent44 to 7 spaces
Nested bullets: 2 spaces per level
- Fruits
  - Apple
  - Banana
- Vegetables
  - Carrot
    - Purple carrot
Preview
  • Fruits
    • Apple
    • Banana
  • Vegetables
    • Carrot
      • Purple carrot
Under a number: 3 spaces
1. Plan
   1. Research
   2. Design
2. Build
   - Frontend
   - Backend
Preview
  1. Plan
    1. Research
    2. Design
  2. Build
    • Frontend
    • Backend

Numbered and bullet items mix freely. The child just has to clear the parent's marker.

Two-digit numbers need 4
10. Tenth step
    - Indented 4 spaces to clear "10. "
11. Eleventh step
Preview
  1. Tenth step
    • Indented 4 spaces to clear "10. "
  2. Eleventh step

"10. " is four characters wide, so 3 spaces would not reach the text and the child would fall out of the list.

What about "always use 4 spaces"? That rule comes from the original Markdown and from Python-Markdown, which MkDocs uses and which requires 4 spaces per level. In CommonMark, 4 spaces also nests under - and 1. because up to 3 spaces beyond the content column are allowed. So 4 spaces is the portable choice, and 2 is the minimum on GitHub. Go past the window, though, and the line stops being a list item: it joins the parent's text, or after a blank line it becomes a code block. See the indentation guide for tabs and the code-block rule.

Task Lists

A task list is a list item that starts with [ ] or [x]. It is a GitHub Flavored Markdown extension rather than core syntax. The Markdown checkbox guide covers where the boxes are clickable, nesting, and tables.

GFM task list
- [x] Write documentation
- [ ] Update screenshots
- [ ] Deploy to production
Preview
  • Write documentation
  • Update screenshots
  • Deploy to production

Keep or Resume Numbering

The usual reason a numbered list restarts at 1 is that something between the items ended it. There are two fixes. The first is better when the extra content belongs to a step: indent it into the item so the list never ends.

Code block inside a step (list continues)
1. Install the package:

   ```sh
   npm install marked
   ```

2. Import it.
3. Call marked.parse().
Preview
  1. Install the package:

    npm install marked
    
  2. Import it.

  3. Call marked.parse().

The fence is indented 3 spaces, the width of 1. plus its space, so it belongs to step 1.

Two lists, second one starts at 3
1. First item
2. Second item

A paragraph that ends the list.

3. Third item
4. Fourth item
Preview
  1. First item
  2. Second item

A paragraph that ends the list.

  1. Third item
  2. Fourth item

When the content really sits between two lists, start the second list at the next number. The blank line before 3. is required.

Tight vs Loose Lists

A blank line between any two items makes the whole list loose: each item is wrapped in a paragraph and gets paragraph spacing. One stray blank line is enough to change every item, so remove them for a compact list.

Tight list (no blank lines)
- Milk
- Eggs
- Bread
Preview
  • Milk
  • Eggs
  • Bread
Loose list (one blank line)
- Milk

- Eggs
- Bread
Preview
  • Milk

  • Eggs

  • Bread

All three items now render as <li><p>…</p></li>, not just the first two.

Platform Variations

Document renderers follow the rules above. Chat and note apps convert list shortcuts as you type, and each has its own limits.

GitHub / GitLabPlatform-specific
- [x] Write documentation
- [ ] Update screenshots
- [ ] Deploy to production
Preview
  • Write documentation
  • Update screenshots
  • Deploy to production

Full GFM lists, including task lists. In issues, pull requests, and comments the checkboxes are clickable; in a README or other .md file they are read-only.

SlackPlatform-specific
* first
* second
Preview
  • first
  • second

The message composer turns * + space into a bulleted list and 1. + space into a numbered one. Messages sent by apps as plain mrkdwn have no list syntax at all; a Block Kit markdown block renders standard - and 1. lists.

DiscordPlatform-specific
- first
  - nested (2 spaces)
- second
Preview
  • first
    • nested (2 spaces)
  • second

Bullets with - or *, numbers with 1., and 2 spaces before the marker to indent a level (per Discord's own guide). Task list brackets show up as plain text.

NotionPlatform-specific
- first
- second
Preview
  • first
  • second

Type -, *, or + then space for a bulleted list, and 1., a., or i. then space for a numbered one. Tab nests the current item, Shift+Tab un-nests it.

Common Mistakes

Almost every broken list is an indentation or blank-line problem. Each row shows the broken version and the fix.

Broken

-First item
-Second item

Fixed

- First item
- Second item
A list marker needs a space (or tab) after it. Without one, the line is ordinary paragraph text.

Broken

1. Parent step
  - Child item

Fixed

1. Parent step
   - Child item
The text after "1. " starts in column 3, so a child needs 3 spaces. With only 2 it is not inside the parent item, and it renders as a separate list underneath.

Broken

- Fruits
  - Apple
 - Banana

Fixed

- Fruits
  - Apple
  - Banana
Banana is indented 1 space, which is less than the 2 its parent's text needs, so it jumps back out and becomes a top-level item next to Fruits. Line children up under the parent's first letter.

Broken

1. Install:

```sh
npm install
```

1. Run it.

Fixed

1. Install:

   ```sh
   npm install
   ```

2. Run it.
An unindented code block ends the list, so the next item starts a brand-new list, and with lazy 1. numbering it shows 1 again. Indent the fence to the item's text (3 spaces under 1.) to keep it inside.

Broken

Remaining steps:
3. Deploy
4. Announce

Fixed

Remaining steps:

3. Deploy
4. Announce
Only a bullet list or a numbered list that starts at 1 can begin directly under a paragraph. Any other start number is read as more paragraph text until you add a blank line.

Broken

- Last item
This was meant to be a new paragraph.

Fixed

- Last item

This is a new paragraph.
A plain line directly under a list item is a lazy continuation: it joins the item's text. Leave a blank line to end the list.

Quick Reference

SyntaxResultNotes
- itemBullet- * + all work; switching starts a new list
1. itemNumberedFirst number sets the start
1) itemNumberedCommonMark/GitHub; not old Reddit
3. itemStarts at 3Needs a blank line above it after a paragraph
- item - childNested bullet2 spaces under -
1. item - childNested under number3 spaces under 1.
1. step more textSecond paragraph in an itemIndent to the item's text
- [ ] taskUnchecked taskGFM extension
- [x] taskChecked taskGFM extension

Platform Support

Basic bullets and numbers work almost everywhere. Nesting depth rules, alternative markers, and task lists are where platforms differ.

PlatformSupported?Notes
CommonMarkYesBullets (- * +), numbers with . or ), any start number, nesting by content column. Task lists are not core syntax.
GitHub / GitLabYesCommonMark lists plus GFM task lists. GitHub's docs say to indent a child to the first character of the parent's text.
VS Code previewYesCommonMark lists; task lists render as read-only checkboxes.
ObsidianYesAny list type nests under any other. Tab and Shift+Tab indent and un-indent selected items.
MkDocs (Python-Markdown)PartialNested items need 4 spaces per level, and a change of marker does not start a new list. Task lists need an extension.
RedditYesSublists need 2 spaces under a bullet and 3 under a number. 1) markers work on www.reddit.com only; use 1. for old Reddit too.
NotionYesMarkdown shortcuts create native list blocks; Tab nests.
DiscordPartialBullets, numbers, and 2-space indented sublists. No task lists.
SlackPartialLists in the composer and in Block Kit markdown blocks. Plain mrkdwn has no list syntax.

Frequently Asked Questions

How do you make a list in Markdown?

Start each line with a marker and a space. A hyphen, asterisk, or plus sign (- item) makes a bulleted list. A number followed by a period (1. item) makes a numbered list.

How do you make a nested list in Markdown?

Indent the child item so its marker lines up with the first character of the parent's text. That is 2 spaces under a - item, 3 spaces under a 1. item, and 4 under a 10. item. Every line at the same level needs the same indent.

How many spaces do you need to indent a nested list?

In CommonMark and GitHub, the minimum is the width of the parent's marker plus its space: 2 under -, 3 under 1. Up to 3 extra spaces also nest, so 4 spaces works under - and 1. too. 4 spaces per level is required in Python-Markdown (MkDocs), which makes it the safest choice if your file has to render in more than one place.

Is it true that nested lists need 4 spaces?

Not in CommonMark or GitHub Flavored Markdown. The rule there is to line the child up with the parent's text, which is 2 spaces under a bullet. The 4-space rule comes from the original Markdown and Python-Markdown, which MkDocs uses. 4 spaces happens to work in both, which is why it is often given as the universal answer.

How do I start a numbered list at a number other than 1?

Start the first item at that number: 3. Third step. The renderer outputs <ol start="3"> and counts up from there. Only the first number matters, and the list needs a blank line above it if it follows a paragraph.

Do I have to number every item correctly?

No. Only the first item's number is used; the rest are ignored. Writing 1. on every line renders 1, 2, 3, which keeps diffs small when you reorder items. Explicit numbers are easier to read in the raw file.

How do I keep the numbering going after a code block or paragraph?

Indent the code block or paragraph so it belongs to the list item above it: 3 spaces under a 1. item. It then sits inside that item and the list continues. If you let it end the list instead, start the next list at the number you want, such as 3.

Can I use 1) instead of 1. for numbered lists?

Yes in CommonMark and GitHub: 1) and 1. both make an ordered list. Switching between them, or between -, *, and +, starts a new list. Some older parsers, including old Reddit, only accept the period.

Why does my list have extra space between items?

A blank line between any two items makes the whole list loose, which wraps every item in a paragraph and adds vertical space. Remove the blank lines between items to get a tight list.

Why is my Markdown list not rendering?

Check for a missing space after the marker, a child indented less than its parent's text, a numbered list starting at something other than 1 directly under a paragraph, or a chat app that does not support list syntax in that context.

Do Discord and Slack support Markdown lists?

Discord does: - or * for bullets, 1. for numbers, and 2 spaces before the marker to indent. Slack's composer builds a list when you type * or 1. followed by a space, but text sent by apps as mrkdwn has no list syntax.