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.
| Platform | Highlighter | Where the canonical list lives |
|---|---|---|
| GitHub, GitLab | Linguist grammars | languages.yml in the linguist repo |
| Discord, Stack Overflow, many editors | highlight.js | SUPPORTED_LANGUAGES.md |
| Obsidian, Docusaurus | Prism | prismjs.com supported languages |
| Python-Markdown, MkDocs, Jekyll (rouge) | Pygments-style lexers | pygments.org lexer docs |
| VitePress, Astro, Starlight | Shiki | Shiki'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.
| Language | Safe identifier | Other aliases and where they work |
|---|---|---|
| JavaScript | javascript, js | jsx, mjs (highlight.js); node (GitHub) |
| TypeScript | typescript, ts | tsx (highlight.js) |
| Python | python, py | python3 (GitHub); ipython (highlight.js) |
| Shell | bash, sh, shell | zsh (GitHub, highlight.js) |
| Shell session with prompts | shellsession | console (GitHub, highlight.js); shell-session (Prism) |
| PowerShell | powershell | pwsh (GitHub, highlight.js); ps1, ps (highlight.js); posh (GitHub) |
| C | c | h (highlight.js) |
| C++ | cpp | c++ (GitHub, highlight.js); cxx, cc (highlight.js) |
| C# | csharp | cs (highlight.js, Prism); c# (GitHub, highlight.js) |
| Java | java | jsp (highlight.js) |
| Kotlin | kotlin | kt, kts (highlight.js, Prism) |
| Go | go | golang (GitHub, highlight.js) |
| Rust | rust | rs (GitHub, highlight.js) |
| Ruby | ruby | rb (all three) |
| PHP | php | none needed |
| Swift | swift | none needed |
| Dart | dart | none needed |
| R | r | none needed |
| Objective-C | objectivec | objc, obj-c (GitHub, highlight.js) |
| Scala | scala | none needed |
| Lua | lua | none needed |
| Perl | perl | pl (highlight.js) |
| Haskell | haskell | hs (highlight.js) |
| Elixir | elixir | ex, exs (highlight.js) |
| HTML | html | xhtml (GitHub, highlight.js); Prism maps it to markup |
| XML | xml | rss, xsd (GitHub, highlight.js) |
| CSS | css | none needed |
| SCSS | scss | none needed |
| SQL | sql | none needed |
| JSON | json | jsonc (GitHub, highlight.js); json5 (GitHub); geojson (GitHub, renders a map) |
| YAML | yaml, yml | none needed |
| TOML | toml | highlight.js treats it as ini |
| INI | ini | dosini (GitHub) |
| Markdown | markdown, md | mkd (highlight.js) |
| LaTeX | latex, tex | none needed |
| GraphQL | graphql | gql (highlight.js) |
| Dockerfile | dockerfile | docker (highlight.js, Prism); Containerfile (GitHub) |
| Makefile | makefile | make (GitHub, highlight.js); mk (highlight.js) |
| Batch | none universal | batch (GitHub, Prism); bat (GitHub, highlight.js); dos (highlight.js) |
| Terraform | none universal | hcl (GitHub, Prism); terraform (GitHub); highlight.js needs a third-party grammar |
| Protocol Buffers | protobuf | proto (GitHub) |
| Diff | diff | patch (highlight.js); udiff (GitHub) |
| Plain text | text | plaintext, txt (highlight.js); plain (Prism) |
| Mermaid | mermaid | renders 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.
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.
diffcolours 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.consoleandshellsessionhighlight the$prompt separately from the command, which reads better thanbashfor terminal transcripts.text,plaintext, andtxtexplicitly 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.