Markdown Code Block Languages: Identifier Cheat Sheet

September 11, 2026 · 10 min read

Markdown Code Block Languages: Syntax Highlighting Identifiers

The markdown code block languages you type after the opening fence (```python, ```ts, ```bash) are decided by the highlighter, not by Markdown. This cheat sheet lists the 50 identifiers and aliases people actually use, shows which ones each platform accepts, and explains what happens when you get one wrong.

Markdown Doesn't Define a Language List

CommonMark calls the text after the opening fence the info string. The spec takes the first word of that string and emits it as a class on the code element, so ```ruby becomes <pre><code class="language-ruby">. That's the whole contract. Markdown never checks whether "ruby" is a real language.

The highlighter that runs afterwards is what turns the class into colours, and each platform picks a different one.

PlatformHighlighterWhere the canonical list lives
GitHub, GitLabLinguist grammarslanguages.yml in the linguist repo
Discord, Stack Overflow, many editorshighlight.jsSUPPORTED_LANGUAGES.md
Obsidian, DocusaurusPrismprismjs.com supported languages
Python-Markdown, MkDocs, Jekyll (rouge)Pygments-style lexerspygments.org lexer docs
VitePress, Astro, StarlightShikiShiki's TextMate grammar list

So the question "which languages work in a markdown language code block?" has no single answer. The practical answer is that the identifiers in the next table work on nearly all of them, and the platform sections after it cover the differences. Fence syntax itself, including indented blocks and escaping backticks, lives in our Markdown code block guide.

Markdown Code Block Language Identifiers: The Big Table

The Safe column is the identifier accepted by GitHub (Linguist), highlight.js, and Prism alike. Aliases listed after it work on some highlighters and not others; the platform column says which.

LanguageSafe identifierOther aliases and where they work
JavaScriptjavascript, jsjsx, mjs (highlight.js); node (GitHub)
TypeScripttypescript, tstsx (highlight.js)
Pythonpython, pypython3 (GitHub); ipython (highlight.js)
Shellbash, sh, shellzsh (GitHub, highlight.js)
Shell session with promptsshellsessionconsole (GitHub, highlight.js); shell-session (Prism)
PowerShellpowershellpwsh (GitHub, highlight.js); ps1, ps (highlight.js); posh (GitHub)
Cch (highlight.js)
C++cppc++ (GitHub, highlight.js); cxx, cc (highlight.js)
C#csharpcs (highlight.js, Prism); c# (GitHub, highlight.js)
Javajavajsp (highlight.js)
Kotlinkotlinkt, kts (highlight.js, Prism)
Gogogolang (GitHub, highlight.js)
Rustrustrs (GitHub, highlight.js)
Rubyrubyrb (all three)
PHPphpnone needed
Swiftswiftnone needed
Dartdartnone needed
Rrnone needed
Objective-Cobjectivecobjc, obj-c (GitHub, highlight.js)
Scalascalanone needed
Lualuanone needed
Perlperlpl (highlight.js)
Haskellhaskellhs (highlight.js)
Elixirelixirex, exs (highlight.js)
HTMLhtmlxhtml (GitHub, highlight.js); Prism maps it to markup
XMLxmlrss, xsd (GitHub, highlight.js)
CSScssnone needed
SCSSscssnone needed
SQLsqlnone needed
JSONjsonjsonc (GitHub, highlight.js); json5 (GitHub); geojson (GitHub, renders a map)
YAMLyaml, ymlnone needed
TOMLtomlhighlight.js treats it as ini
INIinidosini (GitHub)
Markdownmarkdown, mdmkd (highlight.js)
LaTeXlatex, texnone needed
GraphQLgraphqlgql (highlight.js)
Dockerfiledockerfiledocker (highlight.js, Prism); Containerfile (GitHub)
Makefilemakefilemake (GitHub, highlight.js); mk (highlight.js)
Batchnone universalbatch (GitHub, Prism); bat (GitHub, highlight.js); dos (highlight.js)
Terraformnone universalhcl (GitHub, Prism); terraform (GitHub); highlight.js needs a third-party grammar
Protocol Buffersprotobufproto (GitHub)
Diffdiffpatch (highlight.js); udiff (GitHub)
Plain texttextplaintext, txt (highlight.js); plain (Prism)
Mermaidmermaidrenders a diagram on GitHub, GitLab, Obsidian; plain text elsewhere

Case doesn't matter on GitHub or highlight.js, so Python and python behave the same, but lowercase is the convention everywhere and the only form Prism documents.

What Do Three Backticks Do in Markdown, and What About the Language Word?

Three backticks open a fenced code block. Everything until the closing fence is shown literally in a monospace font with no Markdown parsing. Three tildes (~~~) do exactly the same thing, which is handy when your code contains backticks.

The word after the fence is optional. Leave it off and you get a plain block, correctly formatted but uncoloured. Add one and the renderer attaches language-<word> to the block for the highlighter to pick up.

An unknown identifier never causes an error. ```potato renders as a normal code block with no colours, on every platform we know of. That's why typos in the language word go unnoticed for months: the block looks fine, it just isn't highlighted. Compare your identifier against the table above if a block looks flat.

Try Markdown Code Block Languages in the Editor

The demo uses tilde fences so you can see they behave the same as backticks. Change ts to typescript or diff to patch and watch whether the highlighting survives in the preview.

Language identifiers in action

const greet = (name: string): string => hello + name;
Get-ChildItem -Path C:\logs -Filter *.log | Sort-Object Length
- const retries = 3;
+ const retries = 5;
Unknown identifiers still render as a plain code block.

Edit an identifier above and watch the preview.

58 words355 characters20 lines
Markdown

Switch to the Markdown to HTML converter output and look for language-ts on the first block. That class is exactly what CommonMark specifies and all the highlighter ever receives.

Which Languages Work on GitHub, Discord, Obsidian, and VS Code?

GitHub uses Linguist to match the identifier against every language name and alias in languages.yml, which is why c++, c#, and full names like objective-c work there. GitHub also treats four identifiers as diagrams rather than code: mermaid, geojson, topojson, and stl render a flowchart, a map, or a 3D model. Our GitHub Markdown cheat sheet covers the diagram side, and the Mermaid guide shows the syntax.

Discord applies highlight.js colours to code blocks, so the highlight.js aliases in the table are the ones to use: js, py, cs, ps1, patch. Discord's Markdown is its own reduced dialect, and the Discord cheat sheet lists what else it supports.

Obsidian states in its help that it uses Prism for syntax highlighting in reading view. Prism's aliases are fewer than highlight.js's, so powershell, cpp, and sql have no short forms there, and html resolves to Prism's markup grammar. The Obsidian cheat sheet has the rest of the syntax.

VS Code highlights the Markdown preview with its own TextMate grammars, the same ones the editor uses for files. That means any language you have an extension installed for works in the preview. The identifier is that extension's language ID (powershell, csharp, shellscript) or one of the aliases it declares. The VS Code Markdown guide covers the preview setup.

Stack Overflow uses highlight.js with a documented subset and infers the language from the question's tags when you don't specify one. Adding an explicit identifier overrides the inference.

Identifiers That Aren't Languages

A few identifiers change how the block behaves instead of colouring it.

  • diff colours lines starting with + green and - red. There's no way to combine it with another language on GitHub; the block is either a diff or it's Python.
  • console and shellsession highlight the $ prompt separately from the command, which reads better than bash for terminal transcripts.
  • text, plaintext, and txt explicitly disable highlighting. Use one when a block of prose or log output keeps getting misdetected.

A few more are GitHub-specific. mermaid, geojson, topojson, and stl render something visual there and fall back to a plain block elsewhere. math renders LaTeX inside a code fence, an alternative to the $$ delimiters.

One limitation to plan for: there's no portable way to add a title or filename to a fenced block. Hugo, Docusaurus, and MkDocs each have their own syntax for it (title="app.js" after the identifier in Docusaurus), and GitHub ignores all of them. Put the filename in a sentence above the block if it has to work everywhere.

Common Markdown Code Block Language Mistakes

Typing the file extension instead of the identifier. .py and .ts with the dot don't match anything. Drop the dot.

Using c++ on a Prism site. Prism only knows cpp. GitHub and highlight.js accept both, which is why the block worked in your README and not in Obsidian.

Putting a space between the fence and the word. ``` python is valid CommonMark and still highlights, but ```python is the convention every linter expects, and some older renderers only accept the no-space form.

Markdown Code Block Language FAQ

The markdown code block languages table above covers the identifiers you'll reach for in almost every README, note, and doc page. When in doubt, use the full lowercase name (python, not py), because it works on every highlighter. Paste a block into the editor, try an alias, and see whether the preview colours it.