Skip to content
JavaScript js regex 4 min read

Regex Basics

A regular expression (regex) is a pattern that describes a set of strings. In JavaScript, regex is the tool you reach for whenever you need to find, validate, extract, or replace text based on its shape rather than its exact value — checking that an email looks plausible, pulling all the hashtags out of a tweet, or splitting a log line into fields. Regex is built into the language through the RegExp type and a handful of String methods, so there is nothing to install. This page covers the two ways to create a pattern and the most common ways to run it against a string.

Creating a regular expression

There are two equivalent ways to build a pattern: a regex literal and the RegExp constructor. A literal is written between forward slashes and is the form you will use most of the time:

const literal = /hello/;

The constructor takes the pattern as a string and is useful when the pattern is built dynamically at runtime:

const fromString = new RegExp("hello");

Both produce a RegExp object with identical behavior. The key difference is when the pattern is compiled and how special characters are handled.

AspectLiteral /hello/Constructor new RegExp("hello")
SyntaxBetween slashesString argument
CompiledAt parse timeAt runtime
Best forFixed, known patternsPatterns built from variables
EscapingSingle backslash: /\d/Double backslash: "\\d"
FlagsAfter closing slash: /hi/giSecond argument: new RegExp("hi", "gi")

The escaping difference trips people up. Because the constructor receives an ordinary string, every backslash that is meaningful to the regex must itself be escaped for the string literal:

const digit1 = /\d/;                 // matches one digit
const digit2 = new RegExp("\\d");    // same pattern, doubled backslash

Prefer regex literals for static patterns. They are easier to read, catch syntax errors early, and avoid the double-escaping headache. Reach for RegExp only when part of the pattern comes from a variable.

When you build a pattern from user input, interpolate the variable into the constructor:

const term = "report";
const dynamic = new RegExp(`^${term}_\\d+$`);
console.log(dynamic.test("report_2024")); // true

Testing for a match with test()

The simplest question you can ask is “does this string contain the pattern at all?” The RegExp.prototype.test() method answers that with a boolean:

const hasNumber = /\d/;

console.log(hasNumber.test("abc123")); // true
console.log(hasNumber.test("abcdef")); // false
console.log(/cat/.test("concatenate")); // true

Output:

true
false
true

test() is ideal for validation, conditionals, and guard clauses where you only care whether the pattern is present, not where or what it matched:

const isLikelyEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

function validate(input) {
  return isLikelyEmail.test(input)
    ? "looks valid"
    : "invalid email";
}

console.log(validate("[email protected]")); // looks valid
console.log(validate("not-an-email"));       // invalid email

Output:

looks valid
invalid email

Extracting matches with match()

When you need the matched text itself — not just a yes/no — use String.prototype.match(). Its return value depends on whether the pattern has the global g flag.

Without g, match() returns an array-like result for the first match, including capture groups and useful metadata, or null if nothing matched:

const result = "Order #4815 shipped".match(/#(\d+)/);

console.log(result[0]);     // full match
console.log(result[1]);     // first capture group
console.log(result.index);  // position in the string

Output:

#4815
4815
6

Because a failed match returns null, guard before indexing into the result:

const m = "no digits here".match(/(\d+)/);
console.log(m === null ? "no match" : m[1]);

Output:

no match

With g, match() ignores capture groups and instead returns a flat array of every full match (or null if there are none):

const tags = "#js #regex #webdev".match(/#\w+/g);
console.log(tags);
console.log(tags.length);

Output:

[ '#js', '#regex', '#webdev' ]
3

If you need both all matches and their groups or positions, use String.prototype.matchAll(), which returns an iterator of detailed match objects:

const text = "a1 b2 c3";
for (const m of text.matchAll(/([a-z])(\d)/g)) {
  console.log(`${m[1]} -> ${m[2]} at ${m.index}`);
}

Output:

a -> 1 at 0
b -> 2 at 3
c -> 3 at 6

A quick interactive example

The snippet below is self-contained, so you can edit the pattern and string and watch the result change:

const pattern = /\b\w+@\w+\.\w+\b/g;
const text = "Reach us at [email protected] or [email protected].";

const emails = text.match(pattern);
console.log(emails); // [ '[email protected]', '[email protected]' ]

Best practices

  • Use a literal (/pattern/) for fixed patterns and the RegExp constructor only when the pattern is dynamic.
  • Remember to double-escape backslashes inside the RegExp string form ("\\d", not "\d").
  • Use test() when you only need a boolean; it is faster and clearer than checking match() !== null.
  • Always handle the null return from match() before accessing array indices.
  • Choose match() with g for a flat list of matches, but switch to matchAll() when you also need capture groups or positions.
  • Anchor validation patterns with ^ and $ so they match the whole string rather than just a portion of it.
  • Compile a pattern once into a variable instead of re-creating it on every call inside a loop or hot path.
Last updated June 1, 2026
Was this helpful?