/^/
EasyValidation4 min read

Username Regex

Validates that a username is 3 to 16 characters long and contains only letters, digits, underscores, or hyphens.

#validation#username#alphanumeric#form#identifier#user-input

Regex Pattern

^[a-zA-Z0-9_-]{3,16}$

Pattern Breakdown

Hover over a token to see what it does.

^[a-zA-Z0-9_-]{3,16}$
TokenMeaning
^Anchors the match to the start of the string
[a-zA-Z0-9_-]Character class allowing letters, digits, underscores, and hyphens
a-zLowercase letters within the character class
A-ZUppercase letters within the character class
0-9Digits within the character class
_-Underscore and literal hyphen (hyphen placed last so it isn't read as a range)
{3,16}Quantifier requiring between 3 and 16 characters total
$Anchors the match to the end of the string

Detailed Explanation

What it does

This pattern checks that an entire string is a valid username: only letters, digits, underscores, and hyphens are allowed, and the total length must fall between 3 and 16 characters. Any input containing spaces, punctuation, or an out-of-range length is rejected.

Why it works

The character class [a-zA-Z0-9_-] enumerates every acceptable character in one set, so a single quantified class can validate the whole body of the username. The {3,16} quantifier enforces the length constraint directly inside the character class repetition, and the ^ and $ anchors force the class to consume the entire input rather than just a portion of it.

Common use cases

  • Validating sign-up form usernames before submitting to a backend
  • Enforcing consistent handle formatting across a platform (chat apps, forums, games)
  • Sanitizing usernames used in URLs or file paths (e.g. profile.com/username)
  • Client-side input masking to give instant feedback while typing

Edge cases

  • Usernames that are purely numeric, like 12345, are allowed unless additional rules are added
  • Leading or trailing hyphens/underscores (e.g. _user_) are technically valid under this pattern
  • Exactly 3 or exactly 16 characters are valid because the quantifier bounds are inclusive
  • Unicode letters (e.g. accented characters or non-Latin scripts) are rejected since only a-z/A-Z are allowed

Limitations

  • Does not prevent reserved words (admin, root) or profanity — that requires a separate blocklist check
  • Does not enforce that a username starts with a letter, which some systems require
  • No support for internationalized usernames without extending the character class with Unicode ranges

Interactive Tester

Edit the pattern or text below — matching runs live in your browser.

john_doe john-doe123 abc

Test Cases

Editable — add your own inputs to see if they pass.

InputExpectedResult
Pass
Pass
Pass
Pass
Pass
Pass
Pass
Pass

Language Variants

Production-ready examples in 12 languages.

const usernameRegex = /^[a-zA-Z0-9_-]{3,16}$/;
console.log(usernameRegex.test('john_doe')); // true

Common Mistakes

Forgetting the length quantifier and only checking allowed characters, letting a 1-character or 200-character string through

Fix: Always bound the length with a quantifier like {3,16} rather than validating characters alone

Placing the hyphen in the middle of the character class (e.g. [a-z0-9-_]) where it can accidentally form an unintended range

Fix: Put the hyphen first or last inside the character class, e.g. [a-zA-Z0-9_-], so it's always read literally

Using this pattern to also guarantee uniqueness or reserved-word exclusion

Fix: Combine the regex with a database uniqueness check and a blocklist for reserved names

Performance Notes

  • A single bounded character class with {3,16} is O(n) and has no ambiguous repetition, so there is no catastrophic backtracking risk
  • Anchoring with ^ and $ lets the engine reject over-length strings quickly without scanning the whole input
  • Because the class has no overlapping alternatives, this pattern is safe to run on untrusted user input at scale

Browser Compatibility

EngineSupportedNotes
ChromeYes
FirefoxYes
SafariYes
EdgeYes
Node.jsYes