When C# 11 introduced raw string literals, it quietly solved one of the most awkward and long-standing challenges in .NET programming—handling multi-line strings, especially those that include special characters like backslashes, quotes, or need to preserve indentation. Whether you’re building JSON, XML, HTML, SQL queries, or even Regex patterns, you’ll soon find raw string literals indispensable for writing clean, readable, and bug-resistant code.
In this tutorial, we’ll go from the very basics of raw string literals to more advanced, real-world use cases. We’ll write code snippets, explore pitfalls, and even refactor some messy legacy strings into elegant raw strings.
What Are Raw String Literals?
Prior to C# 11, working with strings that spanned multiple lines or included many escape characters was clunky at best. Let’s look at a simple example from pre-C#11 days:
string json = "{\n \"name\": \"Alice\",\n \"age\": 30\n}";
Code language: C# (cs)
Sure, it works. But it’s unreadable and fragile. You need to manually escape every double quote and newline.
Now in C# 11:
string json = """
{
"name": "Alice",
"age": 30
}
""";
Code language: C# (cs)
That’s it. What you see is what you get. Clean. Simple. No escaping necessary. This is a raw string literal.
Basic Syntax of Raw String Literals
Raw string literals are defined using triple double-quotes ("""
) instead of regular double-quotes ("
). The content inside a raw string literal is preserved exactly as typed—spacing, newlines, quotes, everything.
Basic Example
string message = """
Hello, world!
Welcome to raw string literals in C#.
""";
Code language: C# (cs)
This produces exactly the string you see. Line breaks and all.
Including Quotes Inside the String
What if you want to include "
inside your string? With raw string literals, it’s just as easy.
string quote = """
She said, "C# 11 raw strings are awesome!"
""";
Code language: C# (cs)
No escaping needed. The raw string handles it cleanly.
Dealing with More Quotes Inside the String
Let’s say your string contains triple quotes itself. C# 11 allows you to increase the number of quotes to disambiguate.
Example with Triple Quotes Inside the Content
string tricky = """""
This string contains a raw string literal like this: """
"""""";
Code language: C# (cs)
Notice how we opened and closed the string using five double-quotes to accommodate the triple quotes inside.
General rule: if your string includes n
quotes in a row, then use at least n + 1
quotes to define your raw string.
Indentation in Raw Strings
Here’s where raw strings shine even more—multi-line code blocks that keep their indentation.
Let’s take an example of embedding an HTML template:
string html = """
<html>
<head><title>Hello</title></head>
<body>
<p>This is a raw string literal</p>
</body>
</html>
""";
Code language: C# (cs)
Notice that the closing triple quotes are aligned to the indentation you want stripped from the content. Everything before that point is treated as “common leading whitespace” and removed from each line.
If you want no indentation removed, just align the closing """
to the very start of the line:
string html = """
<html>
<head><title>Hello</title></head>
<body>
<p>This is raw string literal</p>
</body>
</html>
""";
Code language: C# (cs)
Raw Strings vs Verbatim Strings (@""
)
You might wonder, “Didn’t we already have multi-line strings with verbatim strings?” Kind of. But not really.
string oldWay = @"This is line one.
This is line two.";
Code language: C# (cs)
The Limitations of Verbatim Strings:
- Quotes still have to be escaped by doubling them (
""
) - No control over leading indentation
- Poor readability for code-like content (e.g., SQL, JSON)
Now compare this:
string json = """
{
"firstName": "John",
"lastName": "Doe",
"isActive": true
}
""";
Code language: C# (cs)
No escaping. No guessing. Just paste your content as-is. Raw strings are the new gold standard for multi-line literals.
Real-World Examples: Refactoring to Raw Strings
Let’s roll up our sleeves and refactor some older style code to raw string literals.
Refactor 1: JSON Configuration
Before (Pre-C# 11):
string config = "{\n \"apiKey\": \"abc123\",\n \"timeout\": 30\n}";
Code language: C# (cs)
After (C# 11):
string config = """
{
"apiKey": "abc123",
"timeout": 30
}
""";
Code language: C# (cs)
Refactor 2: SQL Query
Before:
string query = "SELECT * FROM Users WHERE CreatedAt > '2021-01-01'";
Code language: C# (cs)
Not bad. But what about multi-line queries?
string query = "SELECT Id, Name, Email\nFROM Users\nWHERE IsActive = 1";
Code language: C# (cs)
After:
string query = """
SELECT Id, Name, Email
FROM Users
WHERE IsActive = 1
""";
Code language: C# (cs)
Now your SQL is clean, readable, and easy to copy from SSMS or elsewhere.
Embedding Raw Strings in Interpolated Strings
Raw strings also support interpolation!
Just prefix with $"""
instead of just """
.
string name = "Alice";
string greeting = $"""
Hello, {name}!
Welcome to the new era of strings.
""";
Code language: C# (cs)
And yes, even multi-line interpolations work smoothly:
string section = "Body";
string html = $"""
<html>
<head><title>My Page</title></head>
<{section}>
<p>Hello, world!</p>
</{section}>
</html>
""";
Code language: C# (cs)
Escaping Braces in Interpolated Raw Strings
Here’s a fun one—what if your content contains {
or }
that shouldn’t be treated as interpolation?
You can control this by increasing the number of $
signs used in front of the quote.
string template = $$"""
This is a template with {{braces}} that are not interpolated.
""";
Code language: C# (cs)
Rule of thumb: if your string has n
levels of curly braces, use n + 1
dollar signs to escape them from being interpolated.
Raw Strings in Regex
Regex is notorious for its use of backslashes and quotes. Raw strings make it bearable.
Before:
string pattern = @"^(\d{3})-(\d{2})-(\d{4})$";
Code language: C# (cs)
After:
string pattern = """
^(\d{3})-(\d{2})-(\d{4})$
""";
Code language: C# (cs)
Cleaner. Simpler. No escaping required.
Even better—add interpolation if you want to build patterns dynamically:
string areaCode = "123";
string regex = $"""
^({areaCode})-(\d{{2}})-(\d{{4}})$
""";
Code language: C# (cs)
Multi-Line Logging or Embedded Templates
Imagine writing a big HTML email template or logging a blob of structured text:
string emailTemplate = """
<html>
<body>
<h1>Welcome!</h1>
<p>Thanks for joining our service.</p>
</body>
</html>
""";
Code language: C# (cs)
Or structured logs:
string log = """
[
{ "timestamp": "2025-03-27T15:30:00Z", "level": "INFO", "message": "Startup complete" },
{ "timestamp": "2025-03-27T15:31:00Z", "level": "WARN", "message": "Low memory" }
]
""";
Code language: C# (cs)
Previously, these were a nightmare to format properly. Now? Just paste and go.
Use Cases You’ll Love
Let’s quickly run through some top use cases where raw strings are game-changers:
- ✅ JSON configurations
- ✅ HTML or XML templates
- ✅ SQL queries
- ✅ Email templates
- ✅ Regex patterns
- ✅ Logging formats
- ✅ Markdown blocks
- ✅ Code generation templates (e.g., Roslyn, T4)
Any time you’re pasting content from somewhere and need to preserve format—raw strings are your new best friend.
Common Mistakes and Best Practices
Before we wrap up, let’s touch on some important best practices and common mistakes.
1. Indentation matters.
Always align your closing quotes carefully if you want to preserve indentation. Misaligned quotes can result in surprising leading spaces or trimmed content.
2. Avoid excessive quoting.
If you find yourself using six or more quotes just to wrap content, consider whether you can simplify or split the string.
3. Combine with interpolated raw strings wisely.
Don’t overdo string interpolation. If your raw string has more curly braces than variables, it might be better to avoid interpolation and use string.Replace
instead.
4. Don’t forget about localization.
Raw strings are great, but if you’re building a localizable app, stick to resources for user-visible strings.
5. Don’t abuse them.
Not everything needs to be a raw string. A one-line message? Just use "Hello world"
and move on. Raw strings shine when things get messy.
Mini Code Generator: Generate C# Class from Field List
Now, let’s build a mini code generation tool using raw string literals. This example will dynamically generate a C# class with properties from a list of field names.
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
var className = "Person";
var fields = new List<(string type, string name)>
{
("string", "FirstName"),
("string", "LastName"),
("int", "Age"),
("bool", "IsActive")
};
string classCode = GenerateClass(className, fields);
Console.WriteLine(classCode);
}
static string GenerateClass(string className, List<(string type, string name)> fields)
{
string properties = "";
foreach (var (type, name) in fields)
{
properties += $"""
public {type} {name} {{ get; set; }}
""";
}
string classTemplate = $"""
namespace GeneratedCode
{{
public class {className}
{{
{properties}
}}
}}
""";
return classTemplate;
}
}
Code language: C# (cs)
🔍 Output
namespace GeneratedCode
{
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public bool IsActive { get; set; }
}
}
<code><span style="background-color: initial; font-family: inherit; font-size: inherit; text-align: initial;"></span></code>
Code language: JavaScript (javascript)
Raw string literals make templating like this so much easier and more readable—no escaping, no clunky string concatenation.
C# 11 raw string literals are not just a syntax convenience—they’re a big leap toward code that’s more maintainable, readable, and error-resistant. Whether you’re embedding long templates, writing config data, or just want fewer backslashes in your life, raw strings help you focus on the real logic instead of escaping every little character.
The moment you get comfortable with them, you’ll find yourself cleaning up old code and smiling at how much better it looks. And that’s the mark of a great language feature.