IntelliJ IDEA 2025.2 Help

Tutorial: Get started with Bazel

Bazel is an open-source build and test tool developed by Google. It is designed to manage large codebases with complex dependencies across multiple languages and platforms. Bazel automates the process of compiling code, linking dependencies, running tests, and deploying artifacts.

This tutorial will help you get started with Bazel in IntelliJ IDEA. In the course of completing it, you will:

  • Create a new Bazel project

  • Get acquainted with Bazel project structure and terminology

  • Rename a repository

  • Add Java sources to the project

  • Build and run the project

  • Add a package with Kotlin sources and call it from Java code

  • Get the JAR build artifact

  • Learn how to use project views

Prerequisites

For this tutorial, you only need the Bazel plugin.

Install the Bazel plugin

  1. Press Ctrl+Alt+S to open settings and then select Plugins.

  2. Open the Marketplace tab, find the Bazel plugin, and click Install.

  3. Restart the IDE to activate the plugin.

Create a project

  1. Launch IntelliJ IDEA.

    If the Welcome screen opens, click New Project.

    Otherwise, go to File | New Project in the main menu.

  2. Give your project a name and select Bazel as the build system.

    New Project dialog
  3. (optional) If you want to version this project or later publish it on GitHub, check Create Git repository.

  4. Click Create.

IntelliJ IDEA generates the project files. After that, it synchronizes with Bazel, which might take a while.

Project structure and terminology

If you are new to Bazel, here is a quick tour around the project. It discusses the main concepts and files that define how your Bazel project is built. We'll be referring to these concepts and files later in the tutorial.

If you are already familiar with Bazel, you can skip this section.

Main repository

The project we are looking at is called the main repository. In Bazel terminology, a repository is a collection of files that is used to build software.

Since we are building a Java application, we are going to also need other repositories, such as compiler executables and code dependencies.

Workspace

The workspace is a term used to refer to the collection of all the repositories required to build the main repository.

Modules

Apart from being a repository, our project is also a module. A module is a unit of dependency management in Bazel. Modules are defined in the MODULE.BAZEL file.

In our project, the MODULE.BAZEL file starts with the module declaration, which sets the name and version for the module:

module( name = "null", version = "0.1.0", )

It declares the workspace as a Bazel module for bzlmod (Bazel’s built‑in dependency management system). If a repository is later published to a registry, this declaration gives it a unique identity, roughly equivalent to Maven's artifact coordinates. This will allow other Bazel projects use it as a dependency.

Then, the MODULE.BAZEL specifies the dependencies for working with the Java language and external JVM dependencies:

bazel_dep(name = "rules_java", version = "8.10.0") bazel_dep(name = "rules_jvm_external", version = "6.7")

Both of those dependencies import repositories with required files. You add dependencies by referencing modules. Referencing a module can result in importing a single repository or a collection of repositories.

The rest of the file loads the Maven extension, points to the libraries from Maven Central, and exposes the generated repository to the workspace under the name @maven:

maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven") maven.install( name = "maven", artifacts = [ "junit:junit:4.13.2", ], repositories = [ "https://repo1.maven.org/maven2", ], ) use_repo(maven, "maven")

You can find the generated repositories in the Excluded Directories view including the transitive dependencies.

Packages

A package is a unit of Bazel build process. Packages are identified by a BUILD.BAZEL file in the package directory.

In our project, there are two Bazel packages: one for source code, one for tests:

Two BUILD.BAZEL files in the project view

A package includes all the subdirectories except those with their own BUILD.BAZEL file.

BUILD.BAZEL for the source code package contains the following:

load("@rules_java//java:defs.bzl", "java_binary")

The load() statement imports symbols (like java_binary) from the defs.bzl file. defs.bzl comes from the @rules_java external repository that we are importing in the MODULE.BAZEL file via bazel_dep().

After the symbols are imported, we can use them in this BUILD.BAZEL file.

package(default_visibility = ["//visibility:public"])

The package built-in function sets the package metadata (only visibility for now). In this case, the package visibility is public because we need to reference the package from the tests.

java_binary( name = "Main", main_class = "org.example.Main", srcs = glob(["**/*.java"]), )

The java_binary rule call defines a build target called Main. It builds a JAR file from the Java source files in the package. The main_class attribute specifies the main class of the application. The srcs attribute specifies the source files to include in the JAR.

The BUILD.BAZEL for tests package is similar, but it adds two extra dependencies: one for JUnit, and one for the tested package.

java_test( name = "tests", srcs = glob(["**/*.java"]), test_class = "org.example.MainTest", deps = [ "//src/main/org/example:Main", "@maven//:junit_junit", # JUnit 4 dependency from Maven ], )

In the dependency coordinates, @maven is the repository name and junit_junit is the artifact name.

Review the imported repositories

Every imported module corresponds to one or more repositories in your project. You can review the repositories that your project uses in the bazel-{project name}/external folder:

External dependencies in the project view

If you look into the BUILD.BAZEL file, you'll find that there are fewer dependencies than there are repositories in the external folder. This is because each imported module might depend on more modules. Bazel recognizes such transitive dependencies and imports them for you.

Run Bazel targets

Before proceeding with changes to the project, let us make sure it actually builds and runs. There are several ways to do this. In this tutorial, we'll use the Bazel tool window.

  1. In the right sidebar, click the Bazel icon. Alternatively, select View | Tool Windows | Bazel from the main menu.

    Bazel tool window icon on the right sidebar

    This opens the Bazel tool window, which lists the targets as defined in the BUILD.BAZEL files.

  2. In the Bazel tool window, right-click the Main target and select Run.

    A menu appears on right-clicking the Main target in the Bazel tool window

Alternatively, if a main method is currently in front of you in the editor, you can use the gutter icon to run it.

A menu appears on clicking the gutter icon near the main class

Rename repository and sync changes

As we have seen in the overview, the install() call generates an external Bazel repository for each resolved artifact:

maven.install( name = "maven", artifacts = [ "junit:junit:4.13.2", ], repositories = [ "https://repo1.maven.org/maven2", ], )

Since it sets name to maven, we reference the generated repository as @maven, for example @maven//:junit_junit.

Suppose we want to reference it by another name, for example third-party. For this, let us change the name of the generated repository.

Rename the generated repository

  1. Change the name attribute in the install() and use_repo() calls in MODULE.BAZEL.

    maven.install( # before # name = "maven", name = "third-party", # after artifacts = [ "junit:junit:4.13.2", ], repositories = [ "https://repo1.maven.org/maven2", ], ) # before # use_repo(maven, "maven") use_repo(maven, "third-party") # after
  2. Change the label in BUILD.BAZEL for the test package. This is the only package where the repository name is referenced. Otherwise, it would be necessary to change all the other references as well.

    java_test( name = "tests", srcs = glob(["**/*.java"]), test_class = "org.example.MainTest", deps = [ "//src/main/org/example:Main", # before # "@maven//:junit_junit", "@third-party//:junit_junit", # after ], )

After the project configuration is changed, you need to resync the project for Bazel to pick up the changes.

Resync the project

  • On the toolbar of the Bazel tool window, click the Resync project button.

    The 'Resync project' button on the Bazel tool window's toolbar

Add sources for a dependency

If we go to the definition Ctrl+B of the assertEquals() method that is used in the test package, IntelliJ IDEA brings us to a decompiled version of the class file.

Decompiled version of the JUnit class in

This is because the imported repository only includes the compiled classes and does not include their sources. Let us fix this by instructing Bazel to also include the source code when generating a repository.

Add the sources

  1. Open the MODULE.BAZEL file.

  2. Add the the fetch_sources parameter to the install() call as follows:

    maven.install( name = "third-party", artifacts = [ "junit:junit:4.13.2", ], repositories = [ "https://repo1.maven.org/maven2", ], fetch_sources = True )

For the changes to take effect, we need to resync the project again.

Resync the project

  • On the toolbar of the Bazel tool window, click the Resync project button.

    The 'Resync project' button on the Bazel tool window's toolbar

Let us try navigating to the assertEquals() definition again Ctrl+B:

Editor tab with the open Assert.java file (not decompiled)

These are actual sources for the JUnit class now, not a decompiled version.

Add Kotlin

As the next step, let us add a separate package with a library that uses Kotlin.

Add Kotlin dependency

Add building rules

  • In the MODULE.BAZEL file, paste the statement for importing the rules for Kotlin (rules_kotlin 2.1.8) at the top of the file:

    module( name = "null", version = "0.1.0", ) bazel_dep(name = "rules_java", version = "8.10.0") bazel_dep(name = "rules_jvm_external", version = "6.7") bazel_dep(name = "rules_kotlin", version = "2.1.8") maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven") maven.install( name = "third-party", artifacts = [ "junit:junit:4.13.2", ], repositories = [ "https://repo1.maven.org/maven2", ], fetch_sources = True ) use_repo(maven, "third-party")

After we have added the rules, we can proceed with adding a package with Kotlin sources that will use them.

Add a package with Kotlin sources

  1. Switch to the Project tool window. With the root folder selected, press Alt+Insert or right-click it and select New | Bazel Package.

  2. Give the package a name, for example kotlin_lib.

    A new folder appears with a BUILD.BAZEL file in it.

  3. In the kotlin_lib folder, create the following folder structure: src/main/com/example/mylib.

  4. Move BUILD.BAZEL to newly created src/main/com/example/mylib and add the following code in it:

    load("@rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library") package(default_visibility = ["//visibility:public"]) kt_jvm_library( name = "MyLib", srcs = ["MyLib.kt"] )

    Similar to the Java package, this code:

    • Imports the kt_jvm_library rule from the Kotlin Bazel rules (rules_kotlin). This makes the Kotlin JVM library rule available in this BUILD file.

    • Sets the default visibility for targets in this package to public, meaning any other Bazel package in the project can depend on them.

    • Declares a Kotlin JVM library target named MyLib in Bazel. The target compiles MyLib.kt into a JAR.

  5. In src/main/com/example/mylib, create a file named MyLib.kt with the following content:

    package com.example.mylib fun hello() = println("Hello from Kotlin")

Again, we need to resync the project to apply the changes.

Resync the project

  • On the toolbar of the Bazel tool window, click the Resync project button.

    The 'Resync project' button on the Bazel tool window's toolbar

Call Kotlin from Java

To call the Kotlin library from the Java package, we need to add a dependency on it in the corresponding BUILD.BAZEL file.

Add a dependency on Kotlin package

  1. Open the Project tool window Alt+1.

  2. In the src/main/org/example/BUILD.bazel file, add the deps argument to the java_binary call as follows:

    java_binary( name = "Main", main_class = "org.example.Main", srcs = glob(["**/*.java"]), deps = ["//kotlin_lib/src/main/com/example/mylib:MyLib"] )

Then, we can call the hello() method from the Java package:

Update Java code

  • In the src/main/org/example/Main.java file, add an import statement and the library function invocation as follows:

    package org.example; import com.example.mylib.MyLibKt; // import the library public class Main { public static void main(String[] args) { System.out.println("Hello World!"); MyLibKt.hello(); // call the library function } public static int constant4() { return 4; } }

Then, resync the project one more time:

Resync the project

  • On the toolbar of the Bazel tool window, click the Resync project button.

    The 'Resync project' button on the Bazel tool window's toolbar

Let us run the project and check that the Main Java target builds and runs correctly.

Build and run

  1. In the right sidebar, click the Bazel icon. Alternatively, select View | Tool Windows | Bazel from the main menu.

  2. In the Bazel tool window, right-click the Main target and select Run.

    A context menu with the Run option appears on right-clicking the Main target in the Bazel tool window

The Run tool window opens and shows the following output:

INFO: Build completed successfully, 1 total action INFO: Running command line: bazel-bin/src/main/org/example/Main Hello World! Hello from Kotlin

Get the JAR

So far we have run the project right from IntelliJ IDEA. Let us find the JAR file that we can use to run the project elsewhere.

  1. Open the Project tool window Alt+1.

  2. Navigate to Excluded Directories, then under bazel-bin, locate the directories mirroring the package structure of the project. There you can find the JAR files for both our Kotlin library and the main Java application packages.

    The contents of the bazel-bin directory in the Project tool window

Change the project view

This example project is small. However, if you later find yourself building larger projects with Bazel, there is a feature that will be useful in this case.

Bazel's project view allows you to hide irrelevant packages and only work with those you need right now. This makes the sources easier to navigate and reduces the load on the development environment, which is important in huge monorepos.

Let us assume we are currently working on the Kotlin library and want to hide the Java package. This gives us an opportunity to test this feature in action.

First, we need to create a .bazelproject file. This type of files defines what is included in a Bazel's project view.

Create a .bazelproject file

  1. Open the Project tool window Alt+1.

  2. Under the .bazelbsp folder, locate the .bazelproject file.

    .bazelproject file in the .bazelbsp folder

    The selected label near it indicates that this is the project view that is currently used.

  3. Copy the .bazelbsp/.bazelproject file and paste it in the project root.

  4. In the newly created .bazelproject file, change the directories property to point at the kotlin_lib folder as follows:

    derive_targets_from_directories: true directories: kotlin_lib
  5. In the Project tool window, right-click this file and select Load Project View.

    Only kotlin_lib is visible in the Project tool window

    The Project tool window now only shows the kotlin_lib package.

26 August 2025