Regex for Username Validation Rules — Length, Characters, and Common Patterns
Every signup form needs username rules, but the "right" rules vary by platform. This guide walks through the most common constraints — length, allowed characters, leading character rules, and consecutive special characters — with regex you can drop straight into a form validator.
Common Username Rules
- Length — typically 3 to 20 or 3 to 30 characters
- Allowed characters — letters, digits, underscore, sometimes a dot or hyphen
- No leading digit — many systems require the first character to be a letter
- No consecutive special characters — reject things like
john..doeorjohn__doe - No leading/trailing special characters — reject
_johnorjohn_
Basic Username Regex
A simple rule: start with a letter, 3-20 characters total, letters/digits/underscore allowed:
const basicUsername = /^[a-zA-Z][a-zA-Z0-9_]{2,19}$/;
basicUsername.test('john_doe99'); // true
basicUsername.test('9johndoe'); // false — cannot start with a digit
basicUsername.test('jo'); // false — too short (needs 3+)Allowing Dots and Hyphens (Social Platform Style)
Platforms like Instagram and GitHub allow dots or hyphens but disallow them at the start, end, or consecutively. This needs a negative lookahead:
// 3-20 chars, letters/digits/dot/underscore, no leading/trailing/consecutive special chars
const socialUsername = /^(?!.*[_.]{2})[a-zA-Z0-9](?!.*[_.]$)[a-zA-Z0-9._]{1,18}[a-zA-Z0-9]$/;
socialUsername.test('john.doe'); // true
socialUsername.test('john..doe'); // false — two dots in a row
socialUsername.test('.johndoe'); // false — cannot start with a dot
socialUsername.test('johndoe.'); // false — cannot end with a dot
socialUsername.test('john_doe-99'); // false — hyphen not in the allowed set hereBreaking this down: (?!.*[_.]{2}) is a negative lookahead that rejects any string containing two special characters in a row anywhere; the surrounding groups enforce that the first and last characters are alphanumeric.
GitHub-Style Username Rules
GitHub usernames may only contain alphanumeric characters or single hyphens, and cannot begin or end with a hyphen:
const githubStyle = /^[a-zA-Z0-9](?:[a-zA-Z0-9]|-(?=[a-zA-Z0-9])){0,38}$/;
githubStyle.test('dev-brains-ai'); // true
githubStyle.test('-devbrains'); // false — starts with hyphen
githubStyle.test('dev--brains'); // false — consecutive hyphensBuilding a Configurable Validator
In practice it's cleaner to validate rules separately rather than cramming everything into one giant regex — easier to test and to show specific error messages:
function validateUsername(username) {
const errors = [];
if (!/^.{3,20}$/.test(username)) errors.push('Must be 3-20 characters');
if (!/^[a-zA-Z]/.test(username)) errors.push('Must start with a letter');
if (!/^[a-zA-Z0-9_]+$/.test(username)) errors.push('Only letters, digits, and underscores allowed');
if (/[_]{2,}/.test(username)) errors.push('No consecutive underscores');
return { valid: errors.length === 0, errors };
}
validateUsername('john__doe');
// { valid: false, errors: ['No consecutive underscores'] }Frequently Asked Questions
A common pattern is ^[a-zA-Z][a-zA-Z0-9_]{2,19}$, which requires the username to start with a letter and be 3-20 characters total, allowing letters, digits, and underscores.
Use a negative lookahead like ^(?!.*[_.]{2})[a-zA-Z0-9._]{3,20}$, which rejects any username containing two dots, two underscores, or a dot-underscore pair next to each other.
Most platforms treat usernames as case-insensitive for uniqueness (storing a lowercase version for comparison) while still allowing the user to pick their preferred display casing. Validate the pattern normally, but compare/store a lowercased copy for duplicate checks.