Skip to content

/commands/java/classpath-multiple-jars

java -cp: set the classpath with multiple JARs (lib/* wildcard)

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash) · openjdk version "17.0.20.1" 2026-08-18updated
tool
Java
versions
Java 6+ (lib/* wildcard), --class-path: Java 9+
os
linux, macos, windows

java -cp "out:lib/*" com.example.App runs a class with a class path made of the out folder and every JAR in lib/. Entries are separated by : on Linux and macOS and by ; on Windows, and a trailing * on a directory means "all JAR files in it". Quote the value so the shell does not expand the * itself. -cp, -classpath and --class-path are the same option.

Every JAR in a folder

The example builds two JARs in lib/, a library and the program that uses it, and runs the program with a single wildcard entry:

bash
mkdir -p src/lib src/app classes/lib classes/app lib
echo 'package lib; public class Greeter { public static String hi(String n) { return "hi " + n; } }' > src/lib/Greeter.java
echo 'package app; public class Main { public static void main(String[] a) { System.out.println(lib.Greeter.hi("classpath")); } }' > src/app/Main.java
javac -d classes/lib src/lib/Greeter.java
jar --create --file lib/greeter.jar -C classes/lib .
javac -d classes/app -cp lib/greeter.jar src/app/Main.java
jar --create --file lib/app.jar -C classes/app .
java -cp 'lib/*' app.Main
java -cp lib/app.jar app.Main 2>&1 | head -n 2

Output

hi classpath
Exception in thread "main" java.lang.NoClassDefFoundError: lib/Greeter
	at app.Main.main(Main.java:1)

With only app.jar on the class path, the JVM finds Main but not the lib.Greeter class it needs, so it fails with NoClassDefFoundError at the first call.

Syntax by platform

ShellCommand
bash, zsh (Linux, macOS)java -cp "out:lib/*" com.example.App
Windows cmdjava -cp "out;lib\*" com.example.App
PowerShelljava -cp 'out;lib\*' com.example.App
Git Bash on Windowsjava -cp "out;lib/*" com.example.App (java.exe expects ;)
Environment variableexport CLASSPATH="out:lib/*" then java com.example.App
javacjavac -cp "lib/*" -d out @sources.txt (same syntax at compile time)

Rules for the wildcard

  • Only a trailing * on a directory entry is special: lib/* matches .jar and .JAR files directly in lib. It does not recurse and does not match .class files.
  • The order of JARs matched by * is not specified. If two JARs contain the same class, list them explicitly to control which one wins.
  • An unquoted lib/* is expanded by bash into separate arguments; the JVM then treats the second file as the class to run, and fails with Could not find or load main class naming a JAR file. Always quote it.

Pitfalls

  • -cp with -jar. java -cp lib/* -jar app.jar ignores -cp; with -jar, only the JAR and its manifest Class-Path count. See creating an executable JAR.
  • Current directory dropped. Without -cp and CLASSPATH, the class path is .; once you set -cp, . is no longer included unless you add it.
  • Wrong separator. Using : on Windows makes out:lib/* one entry that does not exist, and the class is not found.
  • NoClassDefFoundError vs ClassNotFoundException. "Could not find or load main class" means the main class itself is missing; NoClassDefFoundError later in the run means a class it uses is missing from the class path.

Confirm it worked

java -verbose:class -cp ... Main lists every class loaded and the JAR it came from; grep for the class you expect.

FAQ

Why does java -cp lib/*.jar not work?

The class path wildcard is a bare * at the end of a directory, as in lib/*. lib/*.jar is not a class path wildcard; an unquoted one is expanded by the shell into several arguments, and java then reads the second JAR as the main class name.

Does lib/* include subfolders or class files?

No. lib/* adds every .jar (and .JAR) file directly inside lib, not JARs in subdirectories and not .class files. Add the directory itself (lib) for loose class files.

Does CLASSPATH still work?

Yes, the CLASSPATH environment variable is used when neither -cp nor -jar is given. A -cp option replaces it completely, which is a common reason a setting seems to be ignored.

Sources