Miller’s Law: Count What You Make People Hold in Mind

By Sergey Nosov

16 October 2026

Here is a function call with nine arguments:

createUser("Alice", "Smith",
  "alice@example.com", 30, "admin",
  true, "UTC", "en-US", 1001);

What does true mean? Does the time zone come before the locale? What is 1001? The call does not say. To find out, you open the definition, match nine parameters to nine positions, and carry the mapping back in your head. Lose one pair, and you misread the call or open the definition again.

The limit behind that strain has a popular name: Miller’s Law. Jon Yablonski’s website Laws of UX states it as “the average person can only keep 7 (plus or minus 2) items in their working memory.” People have used that seven to cap parameter lists, menus, slides, and even billboards. The number overstates the limit, and most of those things are read, not memorized.

This article asks a different question. Not “Are there more than seven?” but “How many things does this design make someone hold at once, and could the page hold them instead?” It covers what Miller actually wrote, later research, where the limit bites and where it does not, and a sensible linter rule. The examples are JavaScript, run on Node.js 24.

What Miller Wrote

George A. Miller, a Harvard psychologist, first read the paper as an invited address to the Eastern Psychological Association in Philadelphia on 15 April 1955. Psychological Review published it in March 1956 as “The Magical Number Seven, Plus or Minus Two: Some Limits on Our Capacity for Processing Information.” It opens with a joke: “My problem is that I have been persecuted by an integer.”

The paper reviews two main kinds of experiments. In tests of absolute judgment, people assign numbers to stimuli that vary along one dimension, such as a tone’s pitch or loudness. Miller averaged the best estimates from these experiments: about 6.5 categories that people could tell apart, with a range from 3 to 15.

In tests of immediate memory, which later research calls short-term memory, people hear a list and repeat it back. Their span, the longest list they could repeat correctly, was about seven items for many kinds of material. It fell only from about nine binary digits to about five monosyllabic English words, though a word carries far more information.

The sevens look like one limit, and Miller called treating them as one process “a fundamental mistake.” He drew the distinction in two sentences: “Absolute judgment is limited by the amount of information. Immediate memory is limited by the number of items.” He called those items chunks and admitted that “we are not very definite about what constitutes a chunk of information.”

The heart of the paper is what people do about the limit. Miller described a demonstration by Sidney Smith. People can repeat about eight decimal digits but only about nine binary digits, which carry far less information. One of Smith’s schemes renamed each group of three binary digits as one digit from 0 to 7. Eighteen binary digits became six octal digits, well within the span.

With larger groups and long practice, Smith’s span reached about forty binary digits. Miller’s lesson was that “recoding is an extremely powerful weapon for increasing the amount of information that we can deal with.”

Miller closed by listing sevens, including the seven wonders of the world, the seven categories for absolute judgment, and the seven digits in the span of immediate memory. He withheld judgment, then added: “But I suspect that it is only a pernicious, Pythagorean coincidence.” The “plus or minus two” appears in the title and nowhere in the text.

In an email Edward Tufte published in 2003, Miller recalled that landscape architects had used the paper to pass local laws restricting the number of items on a billboard. Seven, he wrote, “was a limit for the discrimination of unidimensional stimuli (pitches, loudness, brightness, etc.) and also a limit for immediate recall.” Neither, he added, “has anything to do with a person’s capacity to comprehend printed text.”

The Core Limit Is Closer to Four

Nelson Cowan, a psychologist at the University of Missouri, reviewed the evidence in 2001. Miller’s number, he wrote, “was meant more as a rough estimate and a rhetorical device than as a real capacity limit.” His review concluded that “a single, central capacity limit averaging about four chunks is implicated,” alongside storage that has no capacity limit, such as sensory memory.

Span tasks like the ones Miller reviewed let people rehearse silently and group items as they listen. When experiments block those strategies, the smaller limit appears. In one of Cowan’s own studies, participants repeated the word “the” throughout each trial to prevent rehearsal. They remembered only about three units, whether those were single words or learned pairs. Cowan’s 2010 summary describes “a central memory store limited to 3 to 5 meaningful items in young adults.”

Do not trade one magic number for another. Cowan notes that what people can repeat still depends on the task. The practical reading is modest: a handful of chunks at once, each holding less when the material is new and more when the reader already knows it.

Cowan illustrates the limit with reading. To follow an essay, he writes, a reader may have to hold four ideas at once: the major premise, the previous paragraph’s point, and a fact and an opinion from the current one. “Only when all of these elements have been integrated into a single chunk,” he continues, “can the reader successfully continue to read and understand.”

Reading code is the same kind of work. Midway through a loop, a reader might be holding what the function is for, what a variable currently means, which branch is running, and what the loop has accumulated. That is four things again, about where Cowan puts the limit.

Chunks Belong to the Reader

A chunk is not a property of the code alone; it depends on what the reader has learned. In Miller’s words, “We are dealing here with a process of organizing or grouping the input into familiar units or chunks, and a great deal of learning has gone into the formation of these familiar units.”

Programmers show the same effect. In The Programmer’s Brain (2021), Felienne Hermans retells a 1981 study by Katherine McKeithen and colleagues. Fifty-three beginner, intermediate, and expert programmers studied thirty-line ALGOL programs for 2 minutes and then reproduced them. With real programs, experts outscored intermediates, who outscored beginners. With the lines scrambled, Hermans reports, the three groups barely differed. So the experts’ advantage came not from bigger memories but from chunks for code that made sense.

Conventions are chunks that a whole community shares. Robert C. Martin’s Clean Code (2008) calls new Point(0,0) “perfectly reasonable,” because “the two arguments in this case are ordered components of a single value.” It is warier of assertEquals(expected, actual): “The expected, actual ordering is a convention that requires practice to learn.” Pylint’s documentation draws a similar line. It warns against many positional parameters but counts rgba(1.0, 0.5, 0.3, 1.0) among the sensible exceptions, because the call follows a well-known convention.

Two consequences follow. First, authors are often poor judges of how much their code asks of readers, because they built the chunks while writing it. Code that fits a senior engineer’s working memory may overflow that of someone who joined the team six months ago. Mentoring and documentation help newcomers build their chunk vocabulary faster. Second, consistency is a design tool. A convention, once learned, lets a reader take in a whole pattern as one chunk, and every exception is one more thing to hold separately.

Count What People Must Hold, Not What They Can See

Tufte’s 2003 verdict on the seven-item rule for lists and slides was blunt: “a conclusion which can be sustained only by not reading the paper.” A visible list does not have to be memorized. The reader can look again.

Jakob Nielsen made “Recognition rather than recall” one of his ten usability heuristics in 1994. Its current wording asks for visible elements, actions, and options, so that “the user should not have to remember information from one part of the interface to another.” Raluca Budiu of the Nielsen Norman Group calls a menu the classic example of a recognition-based interface.

Research on menus has long favored breadth over depth. In a 1998 study at Microsoft Research, Kevin Larson and Mary Czerwinski asked nineteen experienced web users to find topics in three hierarchies of 512 encyclopedia entries each. Three levels of eight links, the only layout within seven plus or minus two, was slowest: 58 seconds per search on average. Two levels took 36 seconds with sixteen links at the top and 46 seconds with thirty-two; the authors found no reliable difference between those two.

The authors wrote that they had started out convinced that short-term memory would matter. Instead, the number of levels mattered more, and in their data neither memory span nor visual scanning reliably predicted search times.

Memory mattered in a different way in an earlier study by Snowberry, Parkinson, and Sisson. As Larson and Czerwinski summarize it, errors in its deep menus came from users forgetting the target, or from top-level labels too general to remember the way to it. Larson and Czerwinski suspect the difference lies in method: those participants had to hold the target in mind, while theirs kept it on paper throughout each search.

The earlier study’s single menu of sixty-four items also beat the deeper menus in speed and accuracy, but only when grouped by category. Grouping does for the eye what chunking does for memory. The research points to questions other than the count. Do the labels say what lies behind them? Do related items sit together? How many levels must the user descend, and how long is each list to scan? Even Laws of UX, quoted at the start, warns: “Don’t use the ‘magical number seven’ to justify unnecessary design limitations.”

Working memory does matter where an interface makes users carry something: a code from an email, an answer from step one that step four needs, an error message that vanishes before the user reaches the field. The fix is to let the interface hold it. GOV.UK’s design system requires every validation error to appear twice: in a summary at the top of the page and next to the answer. The summary links to each answer, so the user does not have to remember which fields were wrong.

Where the Limit Bites in Code

Code is visible too, but a menu asks the user to find one item; code, like the essay in Cowan’s example, asks the reader to combine several facts. Many of them live elsewhere: in a definition, in a variable assigned forty lines up, in a convention. That is where the limit bites.

Call Sites

A positional call is a recall task. The reader must remember, or look up, which position means what. Editors such as Visual Studio Code can show parameter names at a call site once you turn the hints on, but a diff in a code review usually does not. Here is the opening call with its definition and an easy-to-miss mistake:

function createUser(
  givenName, familyName, email,
  age, role, active,
  timeZone, locale, tenantId) {
  return { givenName, familyName,
    email, age, role, active,
    timeZone, locale, tenantId };
}

// The time zone and the locale
// trade places. Both are strings,
// so nothing complains.
const user = createUser(
  "Alice", "Smith",
  "alice@example.com", 30,
  "admin", true,
  "en-US", "UTC", 1001);

console.log(user.timeZone);
// Prints: en-US

JavaScript and the function accept the swap, and the program reports en-US as a time zone. ESLint’s documentation for its max-params rule names the cost of many parameters: memorizing each one’s meaning, type, and position.

Names turn the recall task into a recognition task. The meaning moves from the definition to the call site, where the reader can see it. Grouping then turns nine values into two familiar concepts, a profile and an account:

function createUser({
  profile,
  account,
}) {
  const { givenName, familyName,
    email, age,
    timeZone = "UTC",
    locale = "en-US" } = profile;
  const { role, active = true,
    tenantId } = account;
  return { givenName, familyName,
    email, age, role, active,
    timeZone, locale, tenantId };
}

const user = createUser({
  profile: {
    givenName: "Alice",
    familyName: "Smith",
    email: "alice@example.com",
    age: 30,
    timeZone: "UTC",
    locale: "en-US",
  },
  account: {
    role: "admin",
    tenantId: 1001,
  },
});

console.log(user.timeZone);
// Prints: UTC
console.log(user.active);
// Prints: true

The information content is identical. The cognitive cost is not. A swapped time zone and locale now reads wrong at a glance, as timeZone: "en-US". The bare true is now active = true, a default that callers can omit. The function body still handles nine values; the gain goes to every caller and every reader of a call.

One catch: the function silently ignores a misspelled key such as timezone and uses the default time zone. A TypeScript type on the parameter catches that typo when the caller writes the object literal in the call.

Other languages build the idea in. Python’s keyword-only parameters, added in Python 3.0 by PEP 3102, can be filled only by name, never by position. C# has named arguments, which Microsoft’s documentation says make code more readable by showing what each argument represents.

Some linters count positional and keyword arguments differently. Pylint 3.3 (September 2024) added a check for too many positional arguments beside its check for too many arguments in total. RuboCop can leave keyword arguments out of its count; its documentation considers them less complex than positional or optional parameters.

Groups That Deserve a Name

Steve McConnell’s Code Complete (second edition, 2004) notes that in a language with structured data, a composite type with thirteen fields can travel as one mental chunk. Martin Fowler catalogs the move as Introduce Parameter Object; his example replaces a startDate and an endDate, passed together to three functions, with a single date range. Robert C. Martin gives the test for when a group has earned a name: variables that are passed together “are likely part of a concept that deserves a name of its own.”

The test cuts both ways. A date range, an address, or an amount with its currency is a concept most readers already hold, so it arrives as one chunk. A bag of unrelated options called settings is not a chunk. It is nine values with a label on the box, and the reader still has to open the box.

Live Values in a Function

Inside a function, what matters is not the number of lines but how many values a reader must track at the busiest point. McConnell measures each variable’s “live time,” the number of statements from its first reference to its last, and advises keeping it as short as possible. Short lives mean fewer values in play at any one line.

Declare a value next to its first use. When several values exist only to produce one result, move them into a helper that returns the result, so the caller holds one name instead of five values.

Interfaces and Reviews

Nobody holds a whole API in mind, and nobody needs to. A large interface with predictable names and good documentation is a recognition task: the reader finds the few calls a task needs. The cost appears when using one call correctly requires knowing about several others: an initialization order, a flag that changes another method’s meaning, a pair of calls that must match. Those are the things a reader must hold, and they are worth counting.

Code review works the same way. A diff that does one thing asks the reviewer to hold one intention. A diff that mixes a refactoring, a feature, and a configuration change asks for three at once. My article on the anatomy of a good code review argues for one intent per pull request.

The Number in Your Linter

Miller’s seven made its way into programming advice. McConnell’s Code Complete says to “limit the number of a routine’s parameters to about seven,” because “people generally cannot keep track of more than about seven chunks of information at once (Miller 1956).” He offers the step from chunks to parameters as a conjecture. Martin’s Clean Code is stricter: “More than three (polyadic) requires very special justification—and then shouldn’t be used anyway.”

The tools disagree, too. As of October 2026, their default thresholds are:

A spread from three to seven marks a convention, not a measurement. ESLint’s documentation calls the cap itself a convention: “many coders adhere to a convention that caps the number of parameters a function can take.”

So pick a number for your linter, and treat a warning as the start of a conversation, not a verdict. My own rule of thumb is to keep positional parameters below five and to name everything past that. When a function needs more, ask what concept its parameters share before reaching for an options bag.

When Chunking Backfires

A chunk helps only as much as it is automatic. If a helper function’s name says what it does, the reader moves on. If not, the reader opens it and comes back holding two contexts instead of one. When every five lines of logic hide behind a named function, debugging becomes archaeology. An abstraction that hides details the reader needs forces the same trip, and my article on the Law of Leaky Abstractions shows what happens when one leaks.

The idea goes back to Miller’s account of Sidney Smith’s experiment. Before drilling himself, Smith gave each recoding scheme to five participants, who studied it for about 5 or 10 minutes. Their spans grew in every case, but by less than expected. Miller’s explanation was that the translation “must be almost automatic”; otherwise, a participant still translating one group loses part of the next.

Some complexity does not decompose. Compliance rules, financial calculations, and some algorithms are intrinsically complex. Below a certain floor, splitting them loses the fidelity the system requires. In those cases, the right answer is excellent documentation and tests, not forced decomposition.

Performance is a narrow exception. Splitting code into more functions adds calls, and on a hot path that overhead can matter. It is rare, and it should be measured before it is cited as a reason to avoid readable design.

A Checklist for Design and Review

Miller’s Law and the Cognitive Load Principle each have an entry in my Software Development Principles series. The Miller’s Law entry lists warning signs such as multi-step processes that make users remember details from early steps, and inconsistent patterns that prevent chunking. In design and code review, the question to keep asking is whether the person reading this is holding too many things at once. These checks make it concrete:

Miller declined to read anything deep into the recurring sevens, and so should we. The limit is real. It applies to what people must hold rather than to everything in view. The way past it is to give people chunks they already own. Count what your design makes someone hold in mind, then let the page hold the rest.

Further Reading