Markdown has no comment syntax of its own, but two workarounds hide text from the rendered page. The first is an HTML comment. The second abuses a link reference that nothing links to:
<!-- This is a comment. It can span multiple lines, even with blank lines inside. --> [//]: # (This is also a comment. Keep it on one line.)
Which one should you pick?
- Use the HTML comment in almost all cases. It works on GitHub, GitLab, in VS Code, Jupyter, Pandoc and static site generators, it can span many lines, and it’s the only way to comment out a block of Markdown.
- Use
[//]: # (…)for a one-line note that must not end up in the generated HTML. Most renderers copy HTML comments into the page source, where anyone can read them. The link reference trick produces no output at all.
Neither method keeps anything secret, though. Anyone who can read the .md file itself, like everyone who visits a public GitHub repository, can read your comments. Never put passwords, keys, or private notes in them.
I tested every example in this article with commonmark.js (a CommonMark reference implementation), markdown-it, marked, GitHub’s Markdown API, and Pandoc 3.9. For Hugo and Jekyll, I ran their Markdown engines, Goldmark and kramdown. The details, and the gotchas I ran into, are below.
HTML comments vs. the link reference trick
HTML comment <!-- --> | Link reference [//]: # () | |
|---|---|---|
| Hidden on the rendered page | Yes | Yes |
| In the generated HTML source | Usually (GitHub and Hugo remove it) | No |
| Multiple lines | Yes, including blank lines | No blank lines; best kept on one line |
| Inside a sentence | Yes | No, it needs its own line |
| Comment out a block of Markdown | Yes | No |
| Where HTML is turned off | Shown as text, or removed | Still hidden |
HTML comments in Markdown
Markdown lets you mix in HTML, and an HTML comment is valid HTML. It starts with <!-- and ends with -->. Everything in between is hidden, including any Markdown:
## Installation <!-- TODO: add instructions for Windows --> Run the installer and follow the steps. <!-- Notes for the next edit: - Check the screenshots - Ask Anna about the API section -->
The blank lines inside the second comment are fine. CommonMark (the spec behind GitHub’s Markdown and most modern parsers) has a special rule for HTML blocks that start with <!--: they only end at the line that contains -->, not at the first blank line. Every renderer I tested agreed.
That’s also why GitHub’s issue and pull request templates are full of HTML comments. The instructions show up while you type, and disappear once you post. GitHub’s own docs call this hiding content with comments.
Hidden, but often still in the page source
Here’s the catch. Most Markdown renderers don’t delete an HTML comment, they copy it into the HTML they generate. The browser doesn’t show it, but it’s there for anyone who opens the page source. Below this paragraph is a real HTML comment, between two lines of text:
This line is visible.
So is this one. There’s a comment between us.
Right-click this page, choose View Page Source, and search for “Peekaboo”. There it is. commonmark.js, markdown-it, marked, Pandoc (when it writes HTML), and Jekyll’s kramdown all keep HTML comments in their output.
Two platforms I tested remove them:
- GitHub strips HTML comments while rendering. The GitHub Markdown API returned HTML without the comment, and the repository page of a project whose README contains comments (I checked nodejs/node) doesn’t include them either. But the raw README is public, so anyone can still read them there.
- Hugo, with its default setting (
unsafe = false), drops HTML comments completely. More on that in the platform table below.
HTML comment gotchas
Comments don’t nest. A comment ends at the first -->. If you wrap a comment around text that already contains a comment, the rest leaks out onto the page:
<!-- Outer comment <!-- inner comment --> This line shows up on the page, followed by a stray --> -->
Every renderer I tested showed that last line and a literal -->. Remove or rewrite the inner comment first.
Don’t put text after --> on the same line. If a line starts with a comment, the parser treats the whole line as raw HTML. In this example, GitHub shows “Text **after** the comment” with the asterisks, because Markdown isn’t processed there:
<!-- comment --> Text **after** the comment
Don’t indent it by four spaces. Four spaces of indentation turn any line into a code block, so the comment shows up literally, as code. And inside a code block, a comment is just text: it’s always shown.
Some renderers turn HTML off. markdown-it, for example, escapes HTML unless the app using it allows it. With HTML off, my test comment appeared on the page as plain text, angle brackets and all. If you’re not sure whether a platform allows HTML, the link reference trick is the safer bet.
Tools read them too. Some tools use HTML comments as switches, like <!-- markdownlint-disable MD033 --> for the markdownlint linter or <!-- prettier-ignore --> for the Prettier formatter. That’s a feature, but it means a comment that happens to start with one of those words isn’t just a comment.
The link reference trick: [//]: # (comment)
Markdown has reference-style links: you write [text][label] in your text, and define the label somewhere else, on a line of its own. A definition doesn’t produce any output. It only matters when a link uses it. So a definition that no link ever uses is invisible, and that’s the trick:
Some text. [//]: # (This comment doesn't appear anywhere in the output.) More text.
Here’s how to read it: [//] is the label, # is the link destination, and the text in parentheses is the link title. The label and destination can be anything valid. // and # are just a convention that looks a bit like a code comment. According to the CommonMark rules for link reference definitions, a title can be wrapped in parentheses, double quotes, or single quotes. All of these variants were invisible in every renderer I tested:
[//]: # (Parentheses) [//]: # "Double quotes" [//]: # 'Single quotes' [//]: <> (An empty destination) [comment]: <> (A different label) [//]: #
The last one has no comment text at all, and is valid too.
Link reference gotchas
This trick is invisible when it works, and very visible when it doesn’t. These are the rules I found while testing:
- Put a blank line before it. A link reference definition can’t interrupt a paragraph. If the line right above it is text, your “comment” becomes part of that paragraph and shows up on the page, in every renderer I tried. A blank line after it isn’t required, but it doesn’t hurt.
- No blank lines inside. A comment that spans two lines works, but a blank line breaks it, and the text shows up. marked was the only renderer that still hid it.
- No parentheses inside the parentheses.
[//]: # (Call me (maybe))shows up as text in CommonMark parsers and on GitHub, and so does a smiley like:)inside the parentheses. Escaping them as\(and\)works everywhere except marked. Easier: switch to quotes,[//]: # "Call me (maybe)", as long as the text has no double quotes. - Don’t reuse the label. With
[comment]: <> (…)in your file, any[comment]in your text turns into a link.[//]is a label you’re unlikely to type by accident. - It only works as a whole line. You can’t put it in the middle of a sentence. Use an HTML comment for that.
One more thing to know: because it produces no output, tools that convert Markdown drop it. When I converted a file from Markdown to Markdown with Pandoc, the HTML comments survived and the [//]: # comments were gone.
Comment out a block of Markdown
To hide a whole section while you work on it, wrap it in an HTML comment. Headings, lists, bold text, links: none of it is processed inside the comment.
This paragraph is visible. <!-- ## Draft section - A list item - Another one Some **bold** text. --> This paragraph is visible too.
All renderers I tested hid the draft section completely. Put <!-- and --> on lines of their own, as above, and check that the block you’re hiding doesn’t contain a comment already (comments don’t nest).
In VS Code, you don’t have to type it. Select the lines and press Ctrl + / (⌘ + / on a Mac). VS Code’s Markdown support defines <!-- --> as its comment syntax, so the toggle-comment shortcut wraps your selection in an HTML comment.
The link reference trick can’t hide a block. You’d need one definition per line, and it can’t hide headings or lists.
Inline comments
An HTML comment also works in the middle of a sentence. It can even continue on the next line:
The API returns JSON <!-- check: also XML? --> by default.
Result: “The API returns JSON by default.” Watch out for a comment on a line of its own, directly under a line of text, though. In CommonMark parsers, including GitHub, a line that starts with <!-- ends the paragraph. The text above and below become two separate paragraphs. Pandoc’s own Markdown is the exception: it kept them together as one paragraph.
Comments in lists and tables
Commenting out a list item looks easy, but there’s a trap. A comment at the start of the line, between two items, ends the list. You get two lists instead of one, which shows as extra space (or restarted numbering in a numbered list):
- Apples <!-- - Bananas --> - Cherries
The fix is to indent the comment so it belongs to the item above it. Then there’s one list with two items in every renderer I tested:
- Apples <!-- - Bananas --> - Cherries
In Markdown tables, a comment inside a cell works fine: | 1.20 <!-- check this --> |. Commenting out a whole row doesn’t. On GitHub, a row that starts with <!-- ends the table, and every row below it shows up as plain text with pipes. Some parsers instead show <!-- in a cell. To hide a row, cut it and paste it into a comment below the table.
Markdown comments on GitHub, Obsidian, Pandoc and other platforms
Here’s how both methods behave on the platforms people ask about most. “Hidden” means you don’t see it on the rendered page.
| Platform | HTML comment | [//]: # () | Notes |
|---|---|---|---|
| GitHub (READMEs, issues, pull requests) | Hidden, and removed from the page HTML | Hidden | The raw file is still public |
| GitLab | Hidden | Not tested | GitLab’s sanitizer keeps comments in the preview and the Markdown API |
| VS Code preview | Hidden, but in the preview HTML | Hidden | The preview uses markdown-it |
| Obsidian | Use %% instead | Not documented | Native %% comment %%, shown only in Editing view |
| Jupyter (JupyterLab) | Hidden | Hidden | Rendered with marked; the text stays in the .ipynb file |
| Pandoc | Kept in HTML output; dropped in Word, LaTeX/PDF and ODT | Dropped everywhere | --strip-comments removes them from HTML |
| Hugo | Removed by default; kept with unsafe = true | Hidden | Uses Goldmark |
| Jekyll | Kept in the page source | Hidden | Liquid’s {% comment %} removes text completely |
| WordPress | Depends on the plugin | Depends on the plugin | Jetpack’s Markdown block uses markdown-it |
A few notes per platform:
GitHub and GitLab
On GitHub, both methods are hidden in READMEs and other .md files, and in issues, pull requests and comments. I tested both modes of GitHub’s Markdown API (“markdown” for files, “gfm” for issues and comments) and got the same results. GitHub removes HTML comments from the rendered HTML, so they’re not in the page source. They’re still in the file, though: click Raw on any README to see them. A comment is a fine place for a hidden TODO in your README.md, but not for anything private.
GitLab hides HTML comments too. I couldn’t test GitLab directly, because its Markdown API requires a login, but its source code shows that the sanitizer keeps comments in the Markdown preview and the API output. Assume they can end up in the page HTML.
Obsidian
Obsidian has its own comment syntax: wrap text in double percent signs. According to the Obsidian syntax docs, an inline comment can go anywhere in a line, and a block comment starts with %% at the beginning of a line and ends at the next %%. Comments are only visible in Editing view; Reading view hides them.
This is an %%inline%% comment. %% This is a block comment. It can contain blank lines and **Markdown**. %%
The %% syntax only works in Obsidian. On GitHub, the percent signs and the text show up as is. If your notes also end up somewhere else, Obsidian’s docs suggest an HTML comment instead.
Pandoc (Word, PDF and HTML)
When you convert Markdown to Word (.docx), LaTeX or PDF, or ODT with Pandoc, HTML comments disappear: those formats ignore raw HTML. I checked the generated files, and the comment text wasn’t in them. When you convert to HTML, Pandoc keeps the comments, unless you add --strip-comments:
pandoc notes.md --strip-comments -o notes.html
The link reference trick produced no output in any format. Pandoc’s own Markdown is also more forgiving than CommonMark: it accepted parentheses inside the comment, as long as they were balanced.
Hugo and Jekyll
Hugo renders Markdown with Goldmark, and by default it doesn’t render raw HTML (markup.goldmark.renderer.unsafe is false). Other HTML is replaced with a <!-- raw HTML omitted --> placeholder, but Hugo’s source code makes an exception for comments: they’re dropped completely, without a placeholder or a warning. So on a default Hugo site, HTML comments don’t reach your pages at all. Set unsafe = true, and they’re copied into the page source like everywhere else. The link reference trick is hidden either way. I tested both settings with Goldmark itself, which (unlike Hugo) does leave the placeholder behind, and read Hugo’s code for the comment exception.
Jekyll uses kramdown, which keeps HTML comments in the page source. kramdown has its own comment extension, {::comment} … {:/comment}, but in my test with kramdown 2.5.2 it simply became an HTML comment in the output. To really remove text in Jekyll, use Liquid’s comment tag. Jekyll runs Liquid before Markdown, so the text never reaches the page:
{% comment %}
This text is removed before the page is built.
{% endcomment %}
VS Code, Jupyter and WordPress
VS Code’s Markdown preview is built on markdown-it, and JupyterLab renders Markdown cells with marked. I tested both libraries: both methods were hidden. In a notebook, keep in mind that the comment is still in the .ipynb file, which is what you share.
In WordPress, it depends on how you write Markdown. Jetpack’s Markdown block uses markdown-it, so expect the results from my markdown-it test, but check your page source before you rely on it. If an HTML comment does make it into the post, it ends up in the public page source, just like the one in my demo above. See my article on Markdown in WordPress for the options.
Comments in AGENTS.md and CLAUDE.md files
Instruction files for AI coding tools, like AGENTS.md and CLAUDE.md, are plain Markdown. The tool reads the file itself, not a rendered version of it. So whether your comment reaches the model depends on the tool, not on Markdown:
- Unless a tool’s documentation says otherwise, assume the model sees everything in the file, comments included. An HTML comment or a
[//]: #line is just more text in the prompt. - Claude Code is one tool that documents an exception. According to its memory docs, block-level HTML comments in CLAUDE.md files are stripped before the content goes into Claude’s context, so you can leave notes for human maintainers without using up context. Comments inside code blocks are kept, and if Claude opens the file with its Read tool, it sees the comments.
Either way, a comment hides nothing from an agent that can read your repository. Don’t use comments to keep anything from an AI tool, and don’t put secrets in these files.
More resources
- The short version of this article is in my Markdown cheat sheet, together with all other basic syntax.
- Writing a README? See how to write a good README.md.
- Want to know what an .md file is and how to open one? Read what is an MD file.
- New to Markdown? Start with the Markdown introduction.
FAQ
Does Markdown have a comment syntax?
No. Neither the original Markdown, CommonMark, nor GitHub Flavored Markdown defines comments. Everyone uses HTML comments (<!-- comment -->) or the link reference trick ([//]: # (comment)). Some apps add their own, like Obsidian’s %% comment %%.
How do I comment out multiple lines in Markdown?
Put <!-- on a line before the text and --> on a line after it. Blank lines, headings and lists inside are all hidden. In VS Code, select the lines and press Ctrl + / (⌘ + / on a Mac).
Can other people see my Markdown comments?
Yes, if they can see the Markdown file. On a website, HTML comments are usually in the page source too; GitHub and default Hugo sites are exceptions. The [//]: # trick leaves nothing in the HTML, but it’s still in the .md file.
Why does my [//]: # comment show up on the page?
Usually one of three things: there’s no blank line above it, there’s a blank line inside it, or the text in parentheses contains a parenthesis of its own. Add a blank line above, keep it on one line, and switch to double quotes if your text needs parentheses: [//]: # "text (like this)".
How do I add a comment in Obsidian?
Wrap the text in double percent signs: %%like this%%. For a block comment, put %% on its own line before and after the text. Obsidian shows comments in Editing view and hides them in Reading view.
