1. Repository in Gradle: a “warehouse,” not GitHub
In Gradle, the word “repository” does not mean a Git repository, but a place where ready-made libraries live. When a beginner first sees the repositories{} block, it is very easy to think: “Aha, this is something about Git.” But the logic here is different: this is not a “folder with code,” but a “store with cans.” And until you tell Gradle which store to go to, the line in dependencies{} remains just a nice line with colons.
Imagine that you ask someone to buy 3.2% brand X milk. The first question will be: “Where should I buy it?” because milk does not teleport by itself. In the same way, Gradle asks: “Where should I look for the library tools.jackson.core:jackson-databind:3.0.4?” And if there is no answer, it fails honestly with an error: the library was not found, because you did not say where to look for it.
Here is the minimal and most familiar option for the Java world:
repositories {
// Allow Gradle to look for dependencies in Maven Central
mavenCentral()
}
This block is responsible for just one thing: “I allow Gradle to look for dependencies in Maven Central.”
2. Maven Central: start with it
Maven Central is not Maven as a build tool, but a library repository. So the phrase “we are on Gradle” does not conflict at all with the phrase “we take dependencies from Maven Central.” This confusion is normal: half of the Java world has stumbled over exactly this point at some time.
In other words, Gradle can work with Maven-style repositories (they have a clear structure of files and metadata), and the most popular such repository is Maven Central. So “we are on Gradle” and “we take libraries from Maven Central” are absolutely compatible things. It is like “I cook at home” and “I buy groceries at the supermarket”: you cook yourself, but you get the ingredients from a specific place.
In ReadLater Starter, at the start we almost always only need mavenCentral(), because the course deliberately limits the infrastructure. We will not discuss private repositories, corporate mirrors, and other enterprise delights today — not because they do not exist, but because first you need to confidently learn how to walk along an ordinary sidewalk, and only then start jumping on a motorcycle.
3. Dependency coordinates: group:artifact:version
A notation like group:artifact:version is not a decorative style and not some ancient Gradle spell. It is the coordinates of a dependency (they are also often called Maven coordinates), that is, the exact way to say: “I need this library, in this version.” In essence, it is an address, a name, and a version in one line.
Beginners often get the feeling here: “Why can’t I just write jackson and that’s it?” The answer is boring, but honest: because in the world of libraries there are too many name collisions, too many modules inside one family, and too many versions. The coordinate format is exactly the discipline that helps you not drown in this chaos.
In build.gradle.kts, you will see something like this (without diving into the roles of configurations yet):
dependencies {
// Connect a specific library by coordinates: group:artifact:version
implementation("tools.jackson.core:jackson-databind:3.0.4")
}
Let us break the three parts down separately, but without academicism — only what really helps you read dependency lines.
group: “who makes it” and the domain
group is usually a namespace (roughly an “organization/project”) that helps you understand who publishes the library. Very often, group looks like a reversed domain: org.slf4j, ch.qos.logback, tools.jackson.core. This is not a strict law, but a popular tradition: domains are unique, and they are convenient for making “globally unique names.”
Do not confuse this: group is not a package in Java code, although sometimes it looks like one. The match can happen, but it is not a mandatory rule. So think like this: group is “which family or organization the library belongs to.”
Examples of group that we will have in the project:
| Purpose | Example group | Human-readable comment |
|---|---|---|
| JSON (Jackson 3) | tools.jackson.core | Jackson family in version 3 (this is fixed exactly like this in the course) |
| Logging API | org.slf4j | common facade for logging |
| Logging implementation | ch.qos.logback | specific logging implementation |
If you have ever seen old Jackson examples with com.fasterxml.jackson.core, while in our course it is tools.jackson.core, do not worry: that is exactly why it is important to carefully read the coordinates and keep the course baseline in mind. In this lecture, we are simply fixing the skill of “seeing the difference,” and the details about Jackson will come much later.
artifact: “which exact can is on the shelf”
artifact is the name of a specific module/library inside a group. And this is where a very common beginner mistake is hidden: seeing the same group and deciding that it is the same library. In practice, one group almost always contains several artifacts: different modules, different parts of one ecosystem.
Using Jackson as an example, this is easy to see:
dependencies {
// Jackson base module (low-level stuff)
implementation("tools.jackson.core:jackson-core:3.0.4")
// Jackson mapping module (usually the one you need in application code)
implementation("tools.jackson.core:jackson-databind:3.0.4")
}
On the left, tools.jackson.core, the group is the same, but the artifact is different. These are two different libraries from the same family. And yes, sometimes you need both: one provides the basic things, the other provides more “application-level” mapping capabilities. We are not using them in code right now, but we are already learning to read a dependency as a meaningful record, not as noise.
Another example from the logging world, to reinforce the idea “same family, different cans”:
dependencies {
// These dependencies are needed specifically at runtime, not for compiling your code
runtimeOnly("ch.qos.logback:logback-core:1.5.32")
runtimeOnly("ch.qos.logback:logback-classic:1.5.32")
}
One group — ch.qos.logback, but two different artifacts. And that is normal: libraries often have a modular structure.
version: a fixed version as insurance
version is the specific version of the library. It seems simple: just a number. But in a real project, the version directly affects build reproducibility: different versions may behave differently, have different APIs, different bugs, and different dependencies inside. That is why in this course we deliberately fix versions and do not use “floating” variants.
If you leave the version to luck, you are almost guaranteed to get the situation “it works on my machine, but not on yours.” And the course is exactly about not living in the “everyone has their own IDE magic” mode.
Compare two records. The first is good (reproducible):
dependencies {
// Explicitly fix the version — that makes the build repeatable
implementation("org.slf4j:slf4j-api:2.0.17")
}
The second is bad (floating). Even if you ever come across something like this, treat it as a “red flag” for a training project:
dependencies {
// Floating version: it may build today and suddenly break tomorrow
implementation("org.slf4j:slf4j-api:+")
}
We are not diving into version management strategies today — it is enough to understand a simple engineering habit: the version must be explicit, especially in a training project where you need to repeat the instructor’s steps exactly.
4. How Gradle finds a library
It helps to mentally replay at least once what happens when you add mavenCentral() and a dependency line. This removes the feeling of “Gradle downloaded something, but I do not know what exactly.” Under the hood, everything is quite down-to-earth: Gradle goes to the specified repository, looks for the artifact there by coordinates, downloads the required files, puts them into the local cache, and then uses them during compilation and launch.
If you want to picture it visually, you can keep the following scheme in mind:
flowchart TD
A[build.gradle.kts] --> B["repositories: mavenCentral()"]
A --> C["dependencies: group:artifact:version"]
C --> D[Search in Maven Central]
D --> E[Download jar and metadata]
E --> F[Gradle cache on your machine]
F --> G[Project classpath]
G --> H[Compilation and launch]
Pay attention to the classpath moment: this is where libraries end up, and after that your Java code can already import classes from those libraries.
5. ReadLater Starter: where this is in build.gradle.kts
By now you already have the ReadLater Starter scaffold from level 2. And in it, the main character of today’s lecture is the file build.gradle.kts. Not the whole file, but specifically two blocks: repositories{} and lines like group:artifact:version inside dependencies{}.
Below is an example of a neat scaffold that is convenient to read from top to bottom. It includes plugins, a repository, and one dependency as a coordinate demonstration:
plugins {
// Connect Gradle plugins for a Java project and an application
java
application
}
repositories {
// Specify where Gradle should look for libraries
mavenCentral()
}
dependencies {
// Connect a library by coordinates
implementation("tools.jackson.core:jackson-databind:3.0.4")
}
The point of this structure is that the file stops being a “sheet of random words.” It becomes a map: first “what the build can do,” then “where to get libraries,” then “which libraries are needed.” This is the habit that later makes you a person who can look at someone else’s build.gradle.kts without panicking.
If there is no repositories{} block at all, the situation is even more blunt: Gradle simply does not know where to go for the library. And if the repository is specified, but there is an error in the coordinates, it usually says so very directly. Often the message looks something like this (I am showing a shortened fragment because the full output easily eats half the screen and causes sadness):
Could not find tools.jackson.core:jackson-databind:3.0.4.
Searched in the following locations:
- https://repo.maven.apache.org/maven2/tools/jackson/core/jackson-databind/3.0.4/
From a beginner’s point of view, this is a good error: it does not “complain about life,” but literally says: “I went there and did not find it.” Then you check what exactly broke: whether repositories{ mavenCentral() } is missing, or whether you made a mistake in the coordinates.
6. How to read coordinates by eye
In real work, you will rarely “parse coordinates at the board.” Usually you need to open build.gradle.kts and understand within 15 seconds: what dependency this is, which family it belongs to, and how similar it is to neighboring lines. That is why it is useful to train eye reading specifically.
Let us take one line and try to read it as a sentence:
// group = org.slf4j, artifact = slf4j-api, version = 2.0.17
implementation("org.slf4j:slf4j-api:2.0.17")
You can say it like this: “I am connecting the slf4j-api dependency from the org.slf4j group, version 2.0.17.” And immediately it becomes clear that org.slf4j is the family, slf4j-api is the specific module, and 2.0.17 is the fixed version.
Jackson is read in exactly the same way:
// group = tools.jackson.core, artifact = jackson-core, version = 3.0.4
implementation("tools.jackson.core:jackson-core:3.0.4")
You said it, you understood it. And this ability to “read the line” is great protection against copy-paste: you carry fewer “magic spells” and better understand exactly what you are connecting.
If you want to reinforce it, you can keep a small table in mind (or leave such notes in build-file comments, but without fanaticism). Here is an example for our course’s basic libraries:
| What for | Coordinates |
|---|---|
| JSON core | tools.jackson.core:jackson-core:3.0.4 |
| JSON mapping | tools.jackson.core:jackson-databind:3.0.4 |
| Logging API | org.slf4j:slf4j-api:2.0.17 |
| Logging runtime | ch.qos.logback:logback-classic:1.5.32 |
| Logging runtime (core) | ch.qos.logback:logback-core:1.5.32 |
Today our goal is not to connect everything in a row, but to learn to understand what each part of this record means.
7. Typical mistakes when working with repositories and coordinates
Mistake #1: confusing a Maven repository with a Git repository.
Sometimes a student sees the word “repository” and starts thinking about GitHub: “Where is the repository link? Why is it not https://github.com/...?” In a Gradle context, repositories{} is not about source code and not about Git, but about a repository of ready-made artifacts (jar files and metadata) that Gradle downloads.
Mistake #2: forgetting repositories{ mavenCentral() } and trying to “fix” everything except the main thing.
The most annoying situation: the dependency is written correctly, the version is correct, but Gradle simply does not “see” the library because you did not say where to look. A beginner starts changing group, changing version, reinstalling the IDE... but all it takes is adding one repositories{ mavenCentral() } block.
Mistake #3: a typo in one part of the coordinates and the feeling that “Gradle is broken.”
Coordinates are sensitive to characters. An extra dot, the wrong letter, a swapped artifact — and the library will not be found. At the same time, Gradle usually clearly writes what exactly it looked for and where. A useful habit: read the error as a hint, not as an accusation.
Mistake #4: pulling random coordinates from the internet without checking the course baseline.
When you google “jackson dependency,” you will almost certainly see old coordinates and old versions. In a training project, this leads to strange incompatibilities: you have “almost the same thing,” but for some reason it does not compile or behaves differently. The right approach at this stage is to first stick to the coordinates and versions fixed in the course, and only later, with experience, deviate consciously.
Mistake #5: treating group:artifact:version as “three random pieces,” not as an address.
If the coordinates do not form a clear picture, you start being afraid to edit them and turn build.gradle.kts into a sacred tablet that cannot be touched. We need the opposite: you should be able to open the build file and calmly say, “Aha, here is the family, here is the module, here is the version. I understand what I am connecting.” This skill is what everything else is built on later, including meaningful work with HTTP/JSON libraries and logging.
GO TO FULL VERSION