skip to content

What is the 'unnamed module', and what role does the classpath play in the module system?

level: middleimportance: must knowfreq 45%

answer

  1. Classpath code = the unnamed module (one per class loader)
  2. Unnamed module reads all modules + exports all its packages
  3. Named module cannot requires the unnamed module (no name to name)
  4. So named modules can't see classpath code → migrate bottom-up
  5. Automatic module = JAR on module path, gets a name, bridges the gap

basics

~20 s

Even on Java 9+, code loaded from the classpath isn't outside the module system — it all goes into one special bucket called the unnamed module. The unnamed module can read every other module and export all its packages.

solid answer

~50 s

Since Java 9 everything runs inside the module system, so classpath code needed a home: it's placed in the **unnamed module** (one per class loader). The unnamed module is deliberately permissive so old applications keep working — it `reads` every other resolved module (so classpath code can use any module's exported types) and it `exports` all of its own packages. Crucially the relationship is one-way: a *named* module cannot `requires` the unnamed module (it has no stable name to require) and therefore named modules cannot see types that live on the classpath. This is the key migration constraint: as you move JARs onto the module path and they become named, they lose the ability to reach anything still on the classpath, so you generally migrate bottom-up. The unnamed module is the backward-compatibility bridge that makes 'just run on Java 9+' work.

code

java · 9 lines
java
// A named module CANNOT depend on classpath code:
module com.example.lib {
    requires com.example.core;   // OK: a named/automatic module
    // requires <classpath>;     // IMPOSSIBLE: the unnamed module has no name
}

// Mixed launch: app.jar (unnamed module) can still use mods/ modules,
// because the unnamed module reads every resolved module:
//   java -p mods -cp app.jar com.example.app.Main

go deeper

for a junior

Knows that classpath code on Java 9+ lives in something called the unnamed module and still runs normally.

for a middle

Explains the unnamed module reads all modules and exports everything, and that named modules cannot require it, forcing bottom-up migration.

for a senior

Uses the asymmetry to plan migrations, distinguishes unnamed vs automatic modules, and knows there's one unnamed module per class loader.

for a principal

Designs a phased modularization strategy across many libraries, reasons about loader topology and Automatic-Module-Name stability for downstream consumers, and the long-term cost of staying on the classpath.

## Background: after Java 9, *everything* is a module From Java 9 on, the JVM always runs with the module system active. The JDK itself is split into modules (`java.base`, `java.sql`, …). But billions of lines of pre-module code use the plain classpath and have no `module-info`. They must keep working. The bridge is the **unnamed module**. ## What the unnamed module is Think of a **named module** as a module with a `module-info` declaring its name, `requires`, and `exports`. By contrast, **every class loaded from the classpath is put into a single, special module that has no name** — the *unnamed module*. (Precisely: there is one unnamed module per class loader, so the application loader and the platform loader each have their own.) The unnamed module is engineered to behave exactly like the classpath always did, so legacy apps see no change: - It **reads every other module** in the configuration. "Reads" means it can access their exported packages. So classpath code can freely call into any module's public, exported API. - It **exports all of its own packages** — every public type on the classpath is visible (to other classpath code). - It does **not** enforce encapsulation among classpath code: same flat, permissive world as before. ## The asymmetry — the migration trap The permissiveness is **one-directional**: - Unnamed module → named modules: **allowed** (it reads them all). - Named module → unnamed module: **forbidden**. A named module declares dependencies with `requires <module-name>`. The unnamed module has *no name*, so there is nothing to write in a `requires` clause. Therefore **a named module can never read code on the classpath**. Consequence: the moment you take a JAR, give it a `module-info`, and move it to the module path, it becomes a named module — and it instantly loses the ability to use any type that is still sitting on the classpath. If it depended on such a type, compilation/resolution breaks. ## Why this drives migration order Because named code can't reach classpath code, you migrate **bottom-up**: convert leaf libraries (those with no remaining classpath dependencies) to named modules first, then their consumers. A library still on the classpath can keep using already-migrated modules (via the unnamed module's read-all behavior), but a freshly named module cannot reach back down to the classpath. Tools like `jdeps` help find what each JAR needs before you draw its `module-info`. ## Automatic modules: the in-between step To ease this, a plain JAR placed on the *module path* (not the classpath) becomes an **automatic module**: it gets a name (from `Automatic-Module-Name` in its manifest, or derived from the filename), `requires` every other module, and `exports` all packages. Unlike the unnamed module it *has a name*, so a real named module **can** `requires` it. Automatic modules are the stepping stone between classpath JARs and fully declared modules. ## Summary The unnamed module is the classpath, re-expressed inside the module system: a permissive, read-everything/export-everything catch-all that keeps legacy code working — but one that named modules cannot depend on, which is exactly why migration goes from the leaves inward.

  • Why can't a named module just 'requires' the classpath?
    Because requires takes a module name and the unnamed module has none by design — there is no stable identifier to reference, so named modules are sealed off from classpath code.
  • How does an automatic module differ from the unnamed module?
    Both are permissive bridges, but an automatic module (a JAR on the module path) HAS a name, so real named modules can require it; the unnamed module (classpath) has no name and cannot be required.

The unnamed module is an unlisted guest with a master keycard: they can enter every named office (read all modules), but because they're not in the building directory, no office can formally invite them in (no module can require the unnamed module).

saying these in an interview costs you the question

  • Saying classpath code is outside the module system on Java 9+ — it's inside, as the unnamed module
  • Claiming named modules can read the classpath if you add the right flag (they fundamentally cannot requires it)
  • Confusing the unnamed module (classpath) with an automatic module (named JAR on the module path)
  • Thinking there is exactly one unnamed module globally (there is one per class loader)

context