String.prototype.indexOf() returns the first index of a substring, or -1 if it is missing (same API as MDN String.prototype.indexOf()). Learn the optional start position, case sensitivity, empty-string quirks, how to find the next match, how it compares to includes(), five examples, and try-it labs.
01
Kind
Instance method
02
Returns
index or -1
03
Case
Sensitive
04
vs includes
Needs the index
05
Mutates?
No
06
Baseline
Widely available
Fundamentals
Introduction
When you need to know where a substring starts — not only whether it exists — use indexOf(). It returns a zero-based index, or -1 when nothing matches.
The search is case-sensitive. Pass a second argument to start searching later in the string (handy for finding the second occurrence). For a simple yes/no check, prefer includes().
💡
Beginner tip
Test for a miss with === -1 (or !== -1 for a hit). Do not treat 0 as “not found” — index 0 is a valid match at the start of the string.
searchString — the substring to look for. Coerced to a string (undefined becomes "undefined").
position(optional) — start looking at this index (and after). Defaults to 0. Values < 0 behave like 0. Values ≥ str.length skip the search and return -1 (except for an empty needle — see below).
Return value
A number — the first matching index, or -1. Special cases:
Situation
Returns
Substring found
First index ≥ position (e.g. "abc".indexOf("b") → 1)
Substring missing
-1
Empty needle, position inside string
Same as position (default 0)
Empty needle, position ≥ length
str.length
Case differs
-1 (e.g. "Hi".indexOf("hi"))
Negative position
Treated as 0
Common patterns
JavaScript
"Brave new world".indexOf("new"); // 6
"Brave new world".indexOf("w"); // 8
"Brave new world".indexOf("xyz"); // -1
// Next occurrence after the first:
const s = "dog and dog";
const first = s.indexOf("dog"); // 0
const second = s.indexOf("dog", first + 1); // 8
// Existence check (prefer includes for clarity):
s.indexOf("dog") !== -1; // true
s.includes("dog"); // true
Cheat Sheet
⚡ Quick Reference
Goal
Code
First index
str.indexOf(needle)
Search from an index
str.indexOf(needle, start)
Not found?
=== -1
Exists? (boolean)
str.includes(needle) or indexOf !== -1
Case-insensitive
str.toLowerCase().indexOf(needle.toLowerCase())
Last occurrence
str.lastIndexOf(needle)
Snapshot
🔍 At a Glance
Four facts to remember about String.indexOf().
Returns
number
Index or -1
Case
sensitive
Normalize if needed
Miss
-1
Not 0, not false
Mutates
no
Strings stay immutable
Compare
📋 indexOf() vs includes() vs lastIndexOf()
indexOf()
includes()
lastIndexOf()
Result
First index or -1
true / false
Last index or -1
Best for
Need the position
Simple contains checks
Search from the end
Case
Sensitive
Sensitive
Sensitive
Start / fromIndex
Optional position
Optional position
Optional from-index
Hands-On
Examples Gallery
Examples follow MDN String.indexOf() patterns. Use View Output or Try It Yourself for each case.
"w" first appears in "world" at index 8. "new" starts at 6. A missing needle returns -1.
Example 2 — First and Second Occurrence
MDN demo: find "dog", then search again after that index.
JavaScript
const paragraph = "I think Ruth's dog is cuter than your dog!";
const searchTerm = "dog";
const indexOfFirst = paragraph.indexOf(searchTerm);
`The index of the first "${searchTerm}" is ${indexOfFirst}`;
// 'The index of the first "dog" is 15'
`The index of the second "${searchTerm}" is ${
paragraph.indexOf(searchTerm, indexOfFirst + 1)
}`;
// 'The index of the second "dog" is 38'
Lower-casing the haystack (and needle when needed) makes the search ignore capital letters.
Example 4 — Count Occurrences
MDN pattern: walk the string with indexOf in a loop.
JavaScript
const str = "To be, or not to be, that is the question.";
let count = 0;
let position = str.indexOf("e");
while (position !== -1) {
count++;
position = str.indexOf("e", position + 1);
}
count; // 4
An empty needle “matches” at the start position (or at the end if you start past the string). Prefer includes() when you only need a boolean.
Applications
🚀 Common Use Cases
Locate a token — find where a keyword or delimiter starts.
Slice around a match — use the index with slice / substring.
Walk every match — loop with indexOf(needle, pos + 1).
Legacy existence checks — !== -1 in older codebases.
Not for patterns — use regex when you need wildcards or flags.
Prefer includes for booleans — clearer intent for yes/no checks.
🧠 How indexOf() Finds an Index
1
Receive needle + start
Coerce searchString; clamp negative position to 0.
Input
2
Scan forward
Look for the first exact, case-sensitive match at/after position.
Search
3
Handle empty needle
Empty string matches at position (or at length if past the end).
Special
4
✅
Return index or -1
Use the number for slicing, looping, or an existence check.
Important
📝 Notes
indexOf() is case-sensitive.
A miss returns -1 — never confuse that with index 0.
Negative position is treated as 0.
Empty searchString has special return rules (see the table above).
Omitting the needle (or passing undefined) searches for "undefined".
Prefer includes() when you only need a boolean.
Compatibility
Browser & Runtime Support
String.prototype.indexOf() is Baseline Widely available — supported across browsers for many years.
✓ Baseline · Widely available
String.indexOf()
Safe for production. Use indexOf() when you need the match index; prefer includes() for simple true/false checks.
UniversalWidely available
Google ChromeSupported · Desktop & Mobile
Full support
Mozilla FirefoxSupported · Desktop & Mobile
Full support
Apple SafariSupported · macOS & iOS
Full support
Microsoft EdgeSupported · Chromium
Full support
Internet ExplorerNo native support · Use a polyfill
Polyfill
OperaSupported · Modern versions
Full support
Samsung InternetSupported · Android
Full support
BunSupported · JavaScript runtime
Supported
DenoSupported · JavaScript runtime
Supported
Node.jsSupported · Server runtime
Supported
Android WebViewSupported · Modern WebView
Full support
indexOf()Excellent
Bottom line: Use String.indexOf() to locate the first substring index. Remember -1 means missing, searches are case-sensitive, and empty needles have special behavior.
Wrap Up
Conclusion
String.prototype.indexOf() finds the first index of a substring (or -1 if missing), with an optional start position for finding the next match. Reach for includes() when you only need yes/no, and keep case rules and empty-needle quirks in mind.
Normalize case when matches should ignore capitalization
❌ Don’t
Treat index 0 as “not found”
Forget that searches are case-sensitive
Ignore empty-needle special cases
Omit the needle and expect a useful default search
Use indexOf when a boolean is all you need
Summary
Key Takeaways
Knowledge Unlocked
Five things to remember about String.indexOf()
First match index, or -1 when missing.
5
Core concepts
📝01
Returns
index / -1
API
🔎02
Next match
pos + 1
Pattern
❌03
Miss
-1
Bounds
⚡04
vs includes
index vs boolean
Compare
📄05
Mutates
no
Immutable
❓ Frequently Asked Questions
String.prototype.indexOf(searchString, position?) returns the zero-based index of the first occurrence of searchString at or after position. If nothing is found, it returns -1.
Yes. "Blue Whale".indexOf("blue") returns -1. Normalize with toLowerCase() when you need a case-insensitive search.
Compare with -1: str.indexOf(needle) !== -1. For a clearer boolean, prefer str.includes(needle).
With no position (or a position inside the string), it returns that position (default 0). If position is past the end, it returns str.length.
indexOf() returns the first index or -1. includes() returns true or false. Use indexOf when you need the position; use includes for simple yes/no checks.
No. Strings are immutable. indexOf() only reads and returns a number.
Did you know?
indexOf existed long before includes. Older tutorials almost always taught str.indexOf(x) !== -1 for “contains” checks — today str.includes(x) is clearer, but indexOf remains essential whenever you need the actual index.