By WebNest Studio Engineering Team
Advanced Java Tutorial
Build Tools: Maven Basics
As soon as a Java project needs external libraries, a compilation step, packaging into a JAR, and repeatable builds across machines, manually running javac and java stops scaling. Maven is a build automation and dependency management tool built around a single configuration file, pom.xml (Project Object Model), that declares what your project needs and how to build it.
Maven's core philosophy is "convention over configuration": if you follow its standard project layout and naming rules, you get a working build with very little explicit configuration. This predictability is why so many Java projects, tutorials, and onboarding guides default to Maven.
Why it matters
No real Java project is compiled by hand. A build tool downloads the libraries, compiles, runs the tests and packages the result, the same way on every machine and on the build server. Maven is the most widely used one in enterprise Java, and reading a pom.xml is a skill needed from the first day in a job.
The pom.xml Structure
Every Maven project has a pom.xml at its root describing the project's identity and dependencies.
groupId— a reverse-domain-style identifier for the organization or project (e.g.com.webnest).artifactId— the name of this specific project or module (e.g.order-service).version— the project's version, often ending in-SNAPSHOTduring active development.<dependencies>— the list of external libraries the project needs, each with its own groupId, artifactId, and version.<build>— plugin configuration controlling how compilation, testing, and packaging behave.
Dependencies and the Central Repository
Rather than manually downloading .jar files, you declare a dependency's coordinates (groupId, artifactId, version) in pom.xml, and Maven downloads it — along with any of its own transitive dependencies — from Maven Central, a shared public repository that hosts the vast majority of open-source Java libraries. Downloaded artifacts are cached locally in ~/.m2/repository, so subsequent builds (even in other projects using the same library) don't re-download it.
The Maven Build Lifecycle
Maven organizes work into a fixed sequence of phases; running a later phase automatically runs every earlier phase first. This is what makes a single command like mvn package reliably compile, test, and package in one predictable step.
validate— checks the project structure and pom.xml are correct.compile— compiles the main source code (src/main/java) intotarget/classes.test— runs unit tests using a testing framework such as JUnit.package— bundles compiled code into a distributable format, usually a JAR or WAR, intarget/.install— copies the packaged artifact into the local~/.m2repository so other local projects can depend on it.deploy— uploads the final artifact to a remote shared repository for other teams or environments to consume.
Example
A minimal pom.xml declaring a JUnit dependency and running the lifecycle
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.webnest</groupId>
<artifactId>order-service</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
<!-- Terminal: mvn clean package -->
[INFO] --- compiler:compile ---
[INFO] --- surefire:test ---
[INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0
[INFO] --- jar:jar ---
[INFO] Building jar: target/order-service-1.0-SNAPSHOT.jar
[INFO] BUILD SUCCESS
Common Mistakes
- Forgetting that running "mvn package" also runs validate, compile, and test first — you cannot skip earlier phases in the lifecycle.
- Leaving a dependency's
scopeas the default (compile) when it is only needed for tests, bloating the final packaged artifact. - Not understanding transitive dependencies — a declared library can silently pull in dozens of other jars, occasionally causing version conflicts.
- Editing files directly under
target/— it is fully regenerated by the build and should never be hand-edited or committed to source control.
Exercise
This exercise needs Maven installed, so it does not run in the playground. Write a minimal pom.xml for a project with the group id com.example, the artifact id demo and the version 1.0-SNAPSHOT, compiled for Java 17, with JUnit Jupiter 5.10.0 as a test-scoped dependency. Then give the command that deletes old build output, runs the tests and builds the JAR.
Expected result: the command ends with BUILD SUCCESS and creates target/demo-1.0-SNAPSHOT.jar.
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<!-- TODO: groupId, artifactId, version -->
<!-- TODO: properties for the Java version -->
<!-- TODO: the JUnit Jupiter dependency, test scope -->
</project>
# TODO: the command that cleans, tests and packages
Show hints
- The Java version is set with the properties
maven.compiler.sourceandmaven.compiler.target. - A dependency needs a group id, an artifact id and a version;
<scope>test</scope>keeps it out of the final JAR.
Show solution
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
mvn clean package
Quick quiz
1. Which three values identify a Maven artifact?
- A. Name, author, licence
- B. Package, class, method
- C. groupId, artifactId and version
- D. Host, port, path
Show answer
C. Together they are known as the coordinates of the artifact.
2. What does mvn package run?
- A. Every phase of the default lifecycle up to and including package: validate, compile, test, package
- B. Only the packaging step
- C. Only the tests
- D. The clean lifecycle
Show answer
A. Asking for a phase runs all the phases before it.
3. Where does Maven keep downloaded dependencies?
- A. In the project's src folder
- B. In the local repository, by default the .m2 folder in the user's home directory
- C. In the JDK folder
- D. In target
Show answer
B. They are downloaded once from Maven Central and reused by every project.
Interview questions
Explain the Maven build lifecycle.
Show answer
Maven has three lifecycles: clean, default and site. The default lifecycle is a fixed sequence of phases, the main ones being validate, compile, test, package, verify, install and deploy. Running a phase executes every phase before it, so mvn install compiles, tests, packages and then copies the artifact to the local repository.
What are dependency scopes in Maven?
Show answer
A scope says when a dependency is needed. compile, the default, is available everywhere and is packaged. provided is needed to compile but supplied at runtime by the container, such as the servlet API. runtime is not needed to compile but is needed to run, such as a JDBC driver. test is available only to the tests. The scope also decides whether the dependency is passed on to projects that depend on yours.
Key Points to Remember
- Maven uses pom.xml and "convention over configuration" to standardize Java builds.
- Dependencies are declared by coordinates (groupId, artifactId, version) and fetched from Maven Central into the local ~/.m2 cache.
- The build lifecycle runs in strict order: validate, compile, test, package, install, deploy.
- Running a later lifecycle phase always executes every phase before it.
Practice in the playground
Write and run your own code for this topic, or start from the exercise or an example. Runs plain Java 17. Frameworks such as Spring, and databases, are not available here. Your code for each topic is kept in this browser.
Run the examples
Change an input, predict the result, then compare it with the output. Explain why the result changes.
These examples need a JDK project with their libraries on your computer, so they can be copied but not run here. Codelab runs Python, FastAPI backends with SQLite, plain Java 17 and HTML/CSS/JavaScript.
Written by
WebNest Studio Engineering Team
Practical lessons from developers working with Java, Python, React, databases and production systems.
Led by Vansh Duggal, Founder, WebNest Studio · Full-stack & software engineering