Regex for Multiline Text Matching — The m and s Flags Explained

By default, JavaScript regex treats a string as one continuous line: ^ and $ anchor to the very start and end, and . never matches a newline. When you're parsing multi-line log files, config blocks, or markdown, you need the m and s flags to change that behavior — and it's easy to reach for the wrong one.

Default Behavior (No Flags)

const text = 'line one\nline two\nline three';

// Without 'm', ^ and $ only match the start/end of the WHOLE string
text.match(/^line/g);   // ['line']  — only matches "line one" at the very start
text.match(/^line/gm);  // ['line', 'line', 'line']  — matches every line's start

The m (Multiline) Flag

With m, ^ matches right after every newline, and $ matches right before every newline — effectively per-line anchors instead of whole-string anchors.

const log = `INFO: server started
ERROR: connection failed
INFO: retrying
ERROR: timeout`;

const errorLines = log.match(/^ERROR:.*$/gm);
console.log(errorLines);
// ['ERROR: connection failed', 'ERROR: timeout']

The s (Dotall) Flag

By default, . matches "any character except line terminators." The s flag makes it match literally any character, including \n — essential when you need to capture a block that spans multiple lines.

const config = `START
key1=value1
key2=value2
END`;

// Without 's', .* cannot cross newlines, so this fails to match the whole block
config.match(/START(.*)END/);       // null

// With 's', .* happily crosses newlines
config.match(/START(.*)END/s)[1];
// '\nkey1=value1\nkey2=value2\n'

Combining m and s

These flags solve different problems and are often used together — for example, extracting a multi-line block that itself starts with a line-anchored marker:

const doc = `---
title: My Post
date: 2026-07-11
---
Body content goes here.
More body text.`;

// Extract YAML frontmatter: starts at line-start '---', ends at line-start '---'
const frontmatter = doc.match(/^---$(.*?)^---$/ms);
console.log(frontmatter[1]);
// '\ntitle: My Post\ndate: 2026-07-11\n'

Here m lets ^---$ match the delimiter lines anywhere in the document, while s lets .*? (lazy) cross the newlines between them.

Practical Use Cases

  • Log parsing — extract every line matching a pattern with m
  • Config/frontmatter extraction — grab a block between two markers with s
  • Comment stripping — match /\/\*.*?\*\//s to remove multi-line /* ... */ comments
  • Markdown code fences — match content between ```` ``` ```` markers spanning several lines

Frequently Asked Questions

What does the m flag do in JavaScript regex?

The m (multiline) flag changes ^ and $ to match the start and end of each line within the string, instead of only the start and end of the entire string.

What does the s flag do in JavaScript regex?

The s (dotall) flag makes the dot (.) match newline characters as well as every other character. Without it, . matches any character except line terminators.

Can I use the m and s flags together?

Yes. They control different things — m affects ^ and $ anchors, while s affects the dot (.) — and are commonly combined, e.g. /pattern/ms, when parsing multi-line log entries or blocks of text.

Try the Free AI Regex Generator

Describe any validation rule in plain English and get a working regex instantly — no signup required.

Related articles