Reason #47 • February 16th, 2026

Heredocs

Yesterday we created strings using the % percent literal. In the example we used it to create a markdown string, but in practice, if I was creating a multi-line string in a specific format like markdown, I would probably reach for a heredoc instead. A heredoc starts with << followed by an identifier of your choice, and ends when that same identifier appears on a line by itself:

Ruby
name = "Elwin"

markdown = <<MARKDOWN
# Hello, #{name}!

Here's how you write Hello World in Ruby:

```ruby
puts "Hello, world!"
```
MARKDOWN
# => "# Hello, Elwin!\n\nHere's how you write Hello World in Ruby:..."
      
JavaScript
const name = "Elwin";

const markdown = `# Hello, ${name}!

Here's how you write Hello World in Ruby:

\`\`\`ruby
puts "Hello, world!"
\`\`\`
`;
// => "# Hello, Elwin!\n\nHere's how you write Hello World in Ruby:...
      

This has two immediate benefits over the % percent literal:

But there is another, even better version of heredocs in Ruby called "squiggly heredocs". A squiggly heredoc starts with <<~ instead of <<, and it automatically removes the leading whitespace from each line based on the indentation of the closing delimiter:

Ruby
def markdown(name)
  <<~MARKDOWN
    # Hello, #{name}!

    Here's how you write Hello World in Ruby:

    ```ruby
    puts "Hello, world!"
    ```
  MARKDOWN
end

puts markdown("Elwin")
# => "# Hello, Elwin!\n\nHere's how you write Hello World in Ruby:..."
      
JavaScript
function markdown(name) {
  return `# Hello, ${name}!

Here's how you write Hello World in Ruby:

\`\`\`ruby
puts "Hello, world!"
\`\`\``;
}

console.log(markdown("Elwin"));
// => "# Hello, Elwin!\n\nHere's how you write Hello World in Ruby:..."
      

This allows us to indent the entire heredoc content to match the surrounding code, which is perfect since the heredoc will most likely be part of a larger method or class definition.

History

Basic heredocs have been around since Ruby's inception, but the squiggly heredoc was added later in Ruby 2.3, released in 2015.

The idea of heredocs comes from the Unix shell, where they were used to provide multi-line input to commands. Perl was the first programming language to adopt heredocs and, as we have seen, was a huge source of inspiration for Ruby.