# Redcarpet keeps the Markdown parser in C and the HTML rules in the renderer

> Redcarpet wraps the Sundown C parser in a Ruby object that splits parsing switches from output flags. Its extension list covers tables, fenced code blocks, footnotes and strikethrough, and stops there, with no CommonMark mode and no benchmark attached to its speed claim.

**vmg/redcarpet** — The safe Markdown parser, reloaded.

- Repository: https://github.com/vmg/redcarpet
- Stars: 5,077 · Forks: 533
- Language: C
- License: MIT
- Published: 2026-10-14 · Updated: 2026-10-14 · Language: en
- Canonical page: https://hysenlabs.com/projects/vmg-redcarpet

## A Sundown port that splits parsing from rendering

Redcarpet is a Ruby library for Markdown processing whose parser is written in C, standing on the Sundown library by Natacha Porté and Vicent Martí that the project credits as the reason it exists at all. The split between those two layers is what shapes the calling code. A Redcarpet::Markdown instance stores no document: you attach a renderer when you construct it and hand text to Markdown#render later, so one configured object can serve many documents in a row. That design fits Ruby applications that want tables, fenced code blocks, footnotes and strikethrough as separate switches rather than as a single dialect choice. The repository layout shows the boundary directly: `ext/` holds the C extension, `lib/` the Ruby classes, `test/` the suite, and `redcarpet.gemspec` with `Rakefile` sit at the top of the tree. Redcarpet is MIT licensed and its last push to master was on 2026-09-30, well after the v3.6.1 gem published on 2025-03-06, so an installed gem and the repository head are not the same code.

## Thirteen parser switches passed once at construction

Everything that decides what counts as Markdown is passed once, in the second argument of Redcarpet::Markdown.new(renderer, extensions = {}), and nothing is decided per render call. `:no_intra_emphasis` stops emphasis inside words, so `foo_bar_baz` produces no `<em>` tags. `:tables` parses PHP-Markdown style tables, and `:fenced_code_blocks` accepts fences delimited by three or more tildes or backticks with an optional language name at the end of the opening fence. `:disable_indented_code_blocks` cancels the four space rule and is the switch to pair with fences, since leaving both on makes indented blocks and fenced blocks compete for the same lines. `:strikethrough` reads `this is ~~good~~ bad`, `:superscript` reads `this is the 2^(nd) time` and nests contiguous runs, `:underline` turns underscored words into underline output while asterisks stay italic, `:highlight` turns `This is ==highlighted==` into `<mark>highlighted</mark>`, and `:quote` turns `This is a "quote"` into `<q>quote</q>`. `:footnotes` adds a marker such as `This is a sentence.[^1]` resolved by a definition line such as `[^1]: This is a footnote.` placed later in the document. `:lax_spacing` drops the blank line requirement around HTML blocks, and `:space_after_headers` refuses `#this is my header`. The list in README.markdown holds thirteen entries, and none of them is a task list or a dialect selector.

## Eleven HTML flags moved onto the renderer object

Output is configured somewhere else entirely. The two built-in renderers, Redcarpet::Render::HTML and Redcarpet::Render::XHTML, are written in C, and every flag that shapes markup lives on the renderer rather than on the parser. Redcarpet::Render::HTML.new(render_options = {}) accepts `:filter_html` to keep any user-inputted HTML out of the output, `:no_images`, `:no_links` and `:no_styles` to suppress those specific tags, `:escape_html` to escape tags rather than pass them through, `:safe_links_only` to restrict which protocols become links, `:with_toc_data` to attach anchors to headers so sections can be linked, `:hard_wrap` to turn source newlines into `<br>` tags, `:xhtml` for XHTML-conformant tags and always on in Render::XHTML, `:prettify` to add prettyprint classes to `<code>` tags, and `:link_attributes` for a hash of extra link attributes. One precedence rule catches people out: `:escape_html` overrides `:no_styles`, `:no_links`, `:no_images` and `:filter_html`, so a tag that another flag was set to remove comes back as escaped text instead. Passing a renderer class rather than a built object also works, because the library instantiates it with default arguments.

## One gem command, then a parser object reused across documents

Redcarpet installs as a gem. The install compiles native extensions, while the parser itself needs no installed libraries.

```bash
$ [sudo] gem install redcarpet
```

Starting with Redcarpet 3.0 the minimum Ruby version is 1.9.2, or Rubinius in 1.9 mode. Machines still on 1.8.7 have to stay on the 2.3.0 line:

```bash
$ [sudo] gem install redcarpet -v 2.3.0
```

The source can also be cloned directly:

```bash
$ git clone git://github.com/vmg/redcarpet.git
```

A first parser is built once and then kept for the life of the process:

```ruby
# Initializes a Markdown parser
markdown = Redcarpet::Markdown.new(renderer, extensions = {})
```

Rendering passes the text in rather than storing it on the instance, and the documented example comes back as one paragraph element:

```ruby
markdown.render("This is *bongos*, indeed.")
# => "<p>This is <em>bongos</em>, indeed.</p>"
```

Switches and a renderer class go into the same constructor call when tables and bare links are wanted:

```ruby
markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML, autolink: true, tables: true)
```

Output flags belong on the renderer, and this pair drops anchor tags while keeping source line breaks:

```ruby
renderer = Redcarpet::Render::HTML.new(no_links: true, hard_wrap: true)
```

## The autolink entry describes an http link with no protocol

The `:autolink` entry contradicts itself inside one clause. It says links are parsed even when they are not enclosed in angle brackets, then adds that email addresses and http links without protocol, but starting with www, are handled. A link cannot be an http link and have no protocol at the same time, so that second clause only parses if it means scheme-less URLs that begin with the www prefix. Read literally, the entry covers http, https and ftp URLs plus email addresses, and nothing that lacks the www prefix, which leaves a bare hostname unlinked. Nothing published here settles which reading was intended. A second overlap sits between two switches: `:fenced_code_blocks` counts three or more tildes, while `:strikethrough` marks a run with two. When both are enabled, no documented tiebreak covers a line that opens with exactly two tildes, so fences typed by users have to be checked against your own templates rather than assumed safe.

## The speed claim names neither a benchmark nor a rival

Performance is where the wording gives the least. Both renderers are described as implemented in C and hence as offering brilliant performance, several degrees of magnitude faster than other Ruby Markdown solutions. Nothing beside that sentence measures it: no version, no document, no input size, and no rival named on either side of the comparison. No benchmark harness sits in the top-level entries, which run from `.github/` and `Gemfile` through `Rakefile` to `test/`. Nothing in the tree reproduces the claim. Take the gap as several orders of magnitude and you are trusting a phrase. The narrower limits are easier to check. Tables follow PHP-Markdown style rather than the GitHub variant, footnotes follow the same style, no extension covers task lists, and nothing selects a CommonMark dialect. A parser configured to clean up user content with `:escape_html` will hand back escaped markup instead of empty text, which changes what a comment page shows to readers.

## Sundown directly, or RedCloth's stored-document object model

Two alternatives sit within reach of this project, and they differ in approach rather than in dialect. The first is Sundown, the C library underneath. Taking Sundown directly gives you the parser without the Ruby object model that `ext/` and `lib/` add, at the cost of writing a binding yourself and giving up the reuse pattern built around Redcarpet::Markdown. The second is RedCloth, and the documented difference is an API shape rather than output. In the RedCloth API the text to render is held inside the instance, while here it is an argument to Markdown#render, and that is exactly what lets a single configured object serve a long-running process. An application that wants per-document state, or that inspects the parser object after a conversion, has to build that state itself. For CommonMark output, task lists, or a dialect newer than these switches reach, the decision is not between Redcarpet and either alternative, because the gap sits in the parser and no wrapper closes it.

## Conclusion

Adopt Redcarpet when your application runs on Ruby, wants tables, fenced code blocks and footnotes as separately switchable options, and prefers a parser written in C rather than in Ruby. Leave it if you need CommonMark output or task lists, since neither appears in the extension list. Before switching, render one document of real untrusted input twice, once with `:filter_html` and once with `:escape_html`, and check whether escaped markup leaking into a rendered page is something your readers can accept.

## FAQ

### How do I install Redcarpet, and which Ruby version does it need?

Run `gem install redcarpet`; the install compiles native extensions and the parser needs no installed libraries. Starting with Redcarpet 3.0 the minimum Ruby version is 1.9.2, or Rubinius in 1.9 mode, and machines on 1.8.7 have to pin to 2.3.0.

### What is the difference between Redcarpet's extensions and its renderer flags?

Extensions passed to `Redcarpet::Markdown.new` change how text is parsed, covering entries such as `:tables`, `:fenced_code_blocks` and `:footnotes`. Flags passed to `Redcarpet::Render::HTML.new` change the emitted markup, covering entries such as `:filter_html`, `:hard_wrap` and `:link_attributes`.

### Can Redcarpet keep HTML from user input out of the rendered output?

Three flags bear on that. `:filter_html` drops user-inputted HTML, `:escape_html` escapes tags instead and takes precedence over `:no_styles`, `:no_links`, `:no_images` and `:filter_html`, and `:safe_links_only` limits which protocols become links.

### Why does Redcarpet pass text to render instead of storing it on the parser?

The text is passed as an argument to `Markdown#render` rather than kept inside the `Redcarpet::Markdown` instance, unlike the RedCloth API. The stated reason is reusability, so one object built with its settings can serve many parses.

### Does Redcarpet support CommonMark or GitHub style task lists?

No entry in the extension list covers either. The switches run from `:no_intra_emphasis` through `:footnotes` and include PHP-Markdown style tables and footnotes, with no task list option and no switch to select a dialect.

## Sources

- [Issues](https://github.com/vmg/redcarpet/issues)
- [License: MIT](https://github.com/vmg/redcarpet/blob/master/LICENSE)
- [README](https://github.com/vmg/redcarpet/blob/master/README.md)
- [Releases](https://github.com/vmg/redcarpet/releases)
- [vmg/redcarpet on GitHub](https://github.com/vmg/redcarpet)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/vmg-redcarpet
