---
title: "Markdown Code Blocks: Syntax Highlighting in 150+ Languages"
description: "How to write Markdown code blocks — fenced and indented, with syntax highlighting, line numbers, inline code, escape sequences, and tips for technical writing."
date: "2025-11-15"
author: "Markdown Viewer Team"
tags: ["markdown", "code blocks", "syntax highlighting", "GFM"]
cover: "/og.png"
---

If you're writing for a developer audience, code blocks carry half the message. The good news: Markdown supports them out of the box. The better news: with one extra hint, you get syntax highlighting in 150+ languages — for free.

This guide covers everything you need to know about Markdown code blocks: fenced vs. indented, language hints, inline code, edge cases, and the patterns the best technical writers use.

## The three ways to write code in Markdown

Markdown has three code styles, each suited to a different situation:

1. **Inline code** — for short snippets within a sentence
2. **Indented code blocks** — for multi-line code in plain CommonMark
3. **Fenced code blocks** — the modern, language-aware way

You'll use fenced blocks 95% of the time.

## Inline code

Wrap inline code with single backticks:

```md
Run `npm install` to install dependencies.
```

For text that contains a backtick (like the bash `` `command` `` substitution), use **double backticks**:

```md
Use ``code with `backticks` inside`` for tricky snippets.
```

If your inline code starts or ends with a backtick, add a space inside the wrapper:

```md
`` ` `` is the backtick character.
```

## Fenced code blocks

The fenced form is what every modern Markdown renderer supports. It's three backticks on a line by themselves:

````md
```
function greet(name) {
  return `Hello, ${name}!`;
}
```
````

Renders as:

```
function greet(name) {
  return `Hello, ${name}!`;
}
```

The opening fence and closing fence don't need to be on lines by themselves in the strict sense, but the convention is one fence per line for readability.

## Language hints for syntax highlighting

Add a language identifier immediately after the opening fence:

````md
```ts
const greet = (name: string) => `Hello, ${name}!`;
```
````

Renders with TypeScript-specific colors:

```ts
const greet = (name: string) => `Hello, ${name}!`;
```

Most renderers use [highlight.js](https://highlightjs.org), which supports **150+ languages**. Common ones:

| Language     | Hint                                |
| ------------ | ----------------------------------- |
| JavaScript   | `js` or `javascript`                |
| TypeScript   | `ts` or `typescript`                |
| Python       | `py` or `python`                    |
| Shell / bash | `sh`, `bash`, `shell`               |
| HTML         | `html`                              |
| CSS / SCSS   | `css` or `scss`                     |
| JSON         | `json`                              |
| YAML         | `yaml` or `yml`                     |
| SQL          | `sql`                               |
| Markdown     | `md` or `markdown`                  |
| Rust         | `rs` or `rust`                      |
| Go           | `go`                                |
| Java         | `java`                              |
| C / C++      | `c` / `cpp`                         |
| Diff         | `diff`                              |
| Mermaid      | `mermaid` (renders as a diagram)    |

If you're unsure, leave the hint off — most highlighters will autodetect the language with reasonable accuracy.

## Diff blocks for showing changes

The `diff` language hint gives you red/green coloring for additions and removals:

````md
```diff
- const greet = (name) => `Hello, ${name}!`;
+ const greet = (name: string) => `Hello, ${name}!`;
```
````

Use it in PR descriptions, changelogs, and tutorials where you want to highlight what changed.

## Mermaid diagrams in fenced blocks

When you use ` ```mermaid `, our preview renders the code as an actual diagram:

````md
```mermaid
flowchart LR
  Idea --> Draft --> Publish
```
````

This works in [Markdown Viewer](/editor), GitHub, GitLab, and Notion (with extensions). For a full guide, see our [Markdown to PDF post](/blog/markdown-to-pdf-guide) which covers Mermaid in printable output.

## Indented code blocks (the old way)

Before fenced blocks, the only way to write a code block was to indent every line by four spaces:

```md
Normal paragraph.

    function greet(name) {
      return "Hello, " + name;
    }

Another paragraph.
```

This still works in strict CommonMark, but it has serious drawbacks:

- **No language hints** — no syntax highlighting.
- **Easy to break** — change the indent and the block silently becomes prose.
- **Hard to copy-paste** — every line has unwanted leading whitespace.

Use fenced blocks. The indented form is mostly a historical artifact.

## Showing fenced blocks inside Markdown

This is the puzzle that confuses every writer the first time: how do you show ` ```ts ` literally without it becoming a code block?

The answer: use **more backticks** on the outer fence than on the inner one. Four backticks outside, three inside:

`````md
````md
```ts
const x = 1;
```
````
`````

Add a language hint of `md` to the outer fence so the highlighter knows it's a Markdown example.

## Escaping inside code blocks

Inside a code block, **nothing is parsed** — no Markdown, no HTML. That means you can paste:

````md
```html
<script>alert('safe inside a code block')</script>
```
````

…and it shows up as literal text, not as a script. This is why Markdown is safe for displaying code samples even when they look dangerous.

## Long lines and word wrap

Code blocks **don't wrap** by default. Long lines cause a horizontal scrollbar in the preview, which is usually what developers want — code shouldn't reflow.

If your audience prefers wrapping (helpful in narrow embeds), CSS can override the behavior:

```css
pre {
  white-space: pre-wrap;
  word-break: break-word;
}
```

But: wrapped code is hard to copy cleanly. Most renderers default to scrolling for a reason.

## Adding line numbers

Plain Markdown doesn't support line numbers. Three workarounds:

### 1. Use a renderer that adds them automatically

MkDocs Material, Docusaurus, and many docs themes ship a line-number plugin. Configure it once and every code block gets gutter numbers.

### 2. Use the `linenos` attribute (Pandoc-style)

```md
```ts {linenos=true}
const x = 1;
const y = 2;
```
```

Works in MkDocs Material, Hugo, and a handful of other tools. Not portable.

### 3. Highlight specific lines

Even better than numbers: highlight the lines that matter. The syntax varies, but the convention is `{hl_lines=2-4}` after the language:

```md
```ts {3,5-7}
function buildGreeting(name: string) {
  // Not highlighted
  if (!name) {                 // highlighted
    name = "stranger";
  }
  return `Hello, ${name}!`;     // highlighted
  // … etc
}
```
```

Markdown Viewer doesn't currently highlight specific lines, but the language hint and syntax are still preserved.

## Showing terminal commands and output

For shell sessions, use the `bash` (or `console`) hint and prefix prompt lines with `$`:

````md
```bash
$ npm install
$ npm run dev
```
````

Some renderers know to skip the `$` when copying. For mixed prompts and output, the `console` language is a good convention:

````md
```console
$ ls
README.md  package.json  src/
$ pwd
/home/user/project
```
````

This makes it obvious to the reader which lines are commands and which are output.

## Inline code with language hints (kind of)

You can't add a language hint to inline code in standard Markdown, but you can simulate it:

```md
Run `npm install` and then `npm run dev` to start.
```

If you really need highlighted inline code, render to HTML and use a snippet of CSS to color specific token classes. It's rarely worth it.

## Common code block mistakes

**1. Missing the closing fence.** If you forget the closing ` ``` `, every paragraph below becomes part of the code block — until the next fence.

**2. Mixing tabs and spaces inside the block.** This doesn't break the block, but it makes the rendered code ugly.

**3. Wrong language hint.** Misspelling the hint silently falls back to plain text. `typescritp` won't highlight anything.

**4. Indenting the fence.** A fenced block must start at the left edge (or be properly indented inside a list item). Off-indented fences are treated as paragraphs.

**5. Using inline code for multi-line content.** ` `multi\nline` ` becomes a single line. Use a fenced block instead.

## Code blocks in tables (sort of)

Markdown tables don't accept fenced code blocks inside cells. For short snippets, use inline code:

```md
| Command       | Description           |
| ------------- | --------------------- |
| `npm install` | Install dependencies  |
| `npm run dev` | Start the dev server  |
```

For multi-line code, move it outside the table and link from the cell.

## Best practices for writing code blocks

After years of writing technical documentation, a few patterns hold up:

- **Always add a language hint.** Even for "obvious" snippets like JSON.
- **Keep blocks short.** 10–20 lines max. Long blocks get skipped.
- **Annotate with comments**, not surrounding prose. Readers focus inside the block.
- **Test your code.** A broken example is worse than no example.
- **Match the style of the surrounding ecosystem.** TypeScript readers expect `const`, semicolons, and Prettier-like formatting.

## Try it in the editor

Open the [Markdown editor](/editor) and paste a few code blocks. The preview highlights them automatically based on the language hint. The status bar shows how many words your code blocks contribute to your total — we exclude them for an accurate word count.

## Related articles

- [Markdown cheat sheet](/blog/markdown-cheat-sheet) — every Markdown feature on a single page
- [Markdown syntax guide](/blog/markdown-syntax-guide) — CommonMark and GFM, end to end
- [Markdown table guide](/blog/markdown-table-guide) — including code in cells

## Quick reference

````md
`inline code`                       Inline snippet
``inline `with` backticks``         Inline with backticks
```                                 Fenced block (auto)
code
```
```ts                               Fenced with language
const x: number = 1;
```
```diff                             Diff block
- old
+ new
```
```mermaid                          Mermaid diagram
graph LR
  A --> B
```
````

That's everything you need. With the language hint and a fenced block, your readers (and search engines) instantly know what they're looking at.
