Reader

How to Use Kotlin Notebooks for Productive Development

| The JetBrains Blog | Default

Kotlin Notebook is a new interactive environment for JVM developers. This article will cover the main Notebook features and how you can utilize them to improve your productivity. 

How to use Kotlin Notebook

Kotlin Notebook is bundled with IntelliJ IDEA starting from the 2025.1 release, and it is easier than ever to start working with notebooks across various contexts. You can create notebooks in three main ways:

Creating a notebook in a project

From within a project, right-click the source root or a folder in the Project view, then choose New | Kotlin Notebook.

This will create an .ipynb file inside your project. Notebooks are generally placed in notebooks or samples subdirectories, but you can place them anywhere within your project.

Creating a scratch notebook

Imagine you want to experiment with code without having to add new files to your project. The Scratch notebook should come in handy for this. To create a notebook that isn’t part of a specific project, follow these steps:

  • Use the New Scratch File action (Cmd+Shift+N on macOS or Ctrl+Alt+Shift+Insert on Windows/Linux).
  • Select Kotlin Notebook from the list.

This creates a file in the Scratches and Consoles | Kotlin Notebooks directory, and the notebook can be accessed across all projects, making it easy to store random pieces of code and refer to them whenever you need to.

Creating a notebook from the Welcome screen

You can open or create a Kotlin notebook directly from the Welcome screen without even opening a project. Navigate to the Kotlin Notebooks tab and click New Notebook. You’ll be prompted to name the notebook and choose whether it should be saved as a scratch file or within a specified folder.

Basics: Interactive cell execution and kernel control

Kotlin Notebook provides a familiar notebook interface within IntelliJ IDEA, making it easy to run code and manage the execution state. Each notebook consists of cells that can be executed independently or in sequence. The toolbar at the top of the notebook includes controls for running cells and managing the Kotlin kernel:

  • Run a single cell: Click the Run button on the left of a code cell or press Ctrl+Enter/ Cmd+Enter. The cell’s code will run, and the output will appear directly beneath the cell. 
  • Run multiple cells: Click Run All to execute every cell in the notebook from top to bottom. If you want to run all cells below a certain point (for example, to resume from the middle of a notebook), you can right-click that cell and choose Run All Below. This flexibility lets you rerun the entire notebook or just a section without having to run each cell manually.
  • Interrupt execution: If a cell is taking too long or has entered an infinite loop, click the Interrupt button (⏹). This stops the currently running cell without affecting the state of the already executed ones. It’s useful for pausing long-running computations or canceling mistaken operations.
  • Restart or stop the session: Use the Restart Kernel button (🔄) to reset the Kotlin kernel. Restarting will terminate the current session and clear the runtime state, so all variables and imports become unresolved. This is helpful to ensure a clean slate (for example, if you want to run the notebook from scratch or recover from a bad state). You can also stop the session entirely by closing the notebook or using the standard Stop action in the Kotlin Notebook tool window, which shuts down the kernel process.
  • Configure Kotlin notebook: The gear icon on the toolbar opens the Kotlin Notebook settings, where you can adjust the notebook’s configuration. This settings panel lets you control the Kotlin kernel environment, such as the JDK or kernel version used.

Using these controls, you can execute code interactively and manage the notebook’s state, with each executed cell getting a number. 

This is important because the notebook’s state depends on execution order, not just the linear order of cells. For example, if one cell defines a variable and a later cell uses it, you must run them in the correct sequence. Kotlin Notebook will help by marking cells with an asterisk if they haven’t been run yet, and by updating the execution count on each cell as you run it.

Sharing notebooks via Gist and Datalore

One of the advantages of using the standard .ipynb notebook format is the ease with which you can share your work. Kotlin Notebook provides convenient ways to share notebooks with others or publish your results online:

  • GitHub Gist: You can quickly share your current notebook as a GitHub Gist. Simply click the Create Gist button (the icon with the GitHub logo) on the toolbar. The IDE will export your notebook to a Gist on your GitHub account and provide you with the URL, which you send to colleagues, knowing they can view the notebook on GitHub or download it. This is perfect for sharing a quick example or including notebook content in issues and forums. The Gist will contain the notebook in JSON format, which GitHub can render for preview. All code, output, and markdown from your Kotlin notebook are preserved.
  • JetBrains Datalore: Because Kotlin Notebook uses the same file format and Kotlin Jupyter kernel as Datalore, JetBrains’ online data science notebook platform, your notebooks are fully compatible with it. You can simply upload the .ipynb file to Datalore to share it or continue working in the cloud. This means you can collaborate with others by simply moving the notebook to Datalore – no conversion needed. 

By leveraging Gists for quick snippets and Datalore for cloud collaboration, Kotlin Notebook makes sharing results and prototypes effortless. Whether you’re posting a code snippet publicly or working on data analysis with a teammate, you can move from IntelliJ IDEA to the web and back without missing a beat.

Testing REST APIs

Kotlin Notebook provides a powerful tool for backend and API developers: the ability to call and test RESTful APIs directly from your notebook, with full support for HTTP methods, JSON serialization, and IDE-based code completion. This is enabled through integration with Kotlin’s HTTP client, powered by Ktor.

To get started, simply add %use ktor-client to a code cell. This command pulls in a Ktor-based HTTP client and the kotlinx.serialization library, both of which are ready to use. After that, you have access to a pre-configured HTTP client instance in your notebook, available through the http variable.

Strongly-typed HTTP calls: With the HTTP client integration, you can perform HTTP requests with Kotlin code and get typed results. For example, to fetch JSON data from an API, you might write:

val response = http.get("https://jsonplaceholder.typicode.com/todos/1")

response.bodyAsText()

This will perform a GET request and return the response as pretty-printed and highlighted JSON output.

Automatic JSON serialization: The notebook’s HTTP client is integrated with Kotlin Serialization, and your responses can be automatically deserialized:

The Ktor client integration will automatically handle class generation and JSON deserialization itself. This means you get a typed Kotlin object with proper fields, instead of manually dealing with JSON parsing. If you have a pre-defined data class, you can also call the body() method of a response with the appropriate type argument.

Under the hood, this feature relies on the open-source kotlin-jupyter-http-util library, which brings together the Ktor client and serialization for use in notebooks. In practice, it means your Kotlin notebook can act like a full-fledged HTTP client tool (akin to Postman or a REST client), but with the added benefit of being able to script and assert on the responses in Kotlin. This is extremely handy for trying out endpoints, testing microservices, or scraping web APIs – all within the comfort of IntelliJ IDEA.

Working with data: Tables and visualizations

Data explorers will feel at home in Kotlin Notebook. The 2025.1 release enhances how data is displayed and plotted, through tight integration with the Kotlin DataFrame library for tabular data and Kandy for charts. These integrations turn your notebook into an interactive data exploration tool.

DataFrame integration – interactive tables

When you add the DataFrame library, simply by putting %use dataframe in a cell, you gain access to a powerful DSL for data manipulation. It builds type information from the runtime the same way HTTP integration logic does, for example:

Any time you display a DataFrame (for example, by evaluating a variable holding a table or by calling df.head()), Kotlin Notebook will render it using a special UI component rather than plain text. It offers:

  • Scrollable pagination: Large datasets are handled gracefully. Instead of trying to dump thousands of rows, the table output shows a limited number of rows per page and offers navigation controls.
  • Sortable columns: You can sort the table by a column with a single click on its header.
  • Hierarchical data drilling: If your DataFrame has nested data (for example, a column that contains another table or complex objects), you can expand that data inline. Click on cells that contain nested structures to drill down into sub-tables. This approach to exploration is great for hierarchical JSON datasets loaded into DataFrames.
  • Open in separate tabs: Sometimes you want to compare two tables side by side. You can now move a DataFrame output into its own tab within the notebook interface. Each table you open in a new tab stays accessible, so you can switch between multiple data views.
  • Export to file: The output panel now has an Export button (💾). With a couple of clicks, you can export the displayed DataFrame to a file in common formats like CSV, JSON, or XML. This is useful if you’ve transformed some data and want to save the results. By default, the DataFrame will be saved to your project directory, but you can choose any location. The exported data respects the currently displayed state (for instance, if you’ve sorted the view by a column, the export will follow that sorted order, so you get exactly what you see).

It’s also possible to just drop a CSV onto your notebook: necessary code will be automatically generated and executed. You’ll be able to work with the loaded dataframe right away.

With Kotlin DataFrame, you can load CSV and JSON files, as well as SQL query results, into tables and then filter, aggregate, and transform them with Kotlin code. Kotlin Notebook will back you up by displaying each step’s result in a user-friendly way. It’s like having a mini data grid inside your IDE for instant feedback on your data manipulations.

Check out the official documentation to learn more about Kotlin DataFrame’s full capabilities.

Visualizing data with Kandy

No data science notebook is complete without visualization. Kotlin Notebook integrates with Kandy, a plotting library built on LetsPlot by JetBrains and created by the Kotlin team to deliver the best experience when working with Kotlin DataFrame and Kotlin Notebook. Run %use kandy in a cell to load the Kandy library and enable its rendering support in the notebook. This allows you to create charts using Kandy’s simple, type-safe DSL and have them appear right below your code.

For example, you can quickly produce a line chart for a DataFrame, df, with the columns Year and Population:

%use kandy

df.plot {

    line {

        x(Year)

        y(Population)

  width = 3.5

  color = Color.LIGHT_BLUE

    } 

layout.title = "Population Growth"

}

When you execute this cell, a chart will be displayed in the notebook output area.

You can see many examples of charts in the Kandy documentation and gallery.

Exporting and copying plots: You can easily save your charts or copy them. Every plot output has an output menu (accessible via a small icon that appears at the top-right of the output when you hover over it). From this menu, select Export Plot As… to save the chart as an image file. 

If you need to use the plot in another application immediately, you can choose Copy Plot, which will copy the chart image to your clipboard so you can paste it into a document or chat. This workflow makes sharing visual insights from your data trivial: run a cell to create a chart, then export or copy that visualization in just a couple of clicks.

Kandy’s plotting capabilities, combined with DataFrame, enable a smooth data exploration experience. You can load and prepare data in a table and then visualize patterns with a chart – all in Kotlin. You can even iterate, adjusting your data transformation and re-running the plot cell to see updates instantly. Kotlin Notebook ensures the charts render efficiently inside the IDE, so you don’t have to switch to an external browser for interactive visuals. For more advanced usage (like interactive plots or complex layouts), refer to the Kandy documentation, but for most needs, a few lines of Kotlin code will produce the desired chart.

Using JVM libraries and project code

Kotlin has a rich ecosystem of libraries and integrates seamlessly with Java. Kotlin Notebook embraces these strengths by allowing you to bring in external libraries or your project’s own code into a notebook session easily.

Adding external libraries with %use and USE {}

You have two primary options when it comes to using a third-party JVM library (for example, an HTTP client, a CSV parser, or a machine learning toolkit) in your notebook:

  • Integrated libraries via %use: Kotlin Notebook comes with a collection of pre-defined library descriptors for many popular libraries (Kotlin DataFrame, Kandy, Ktor, KotlinDL, etc.). You can import these libraries with the magical %use libraryName, without the need to think about dependencies! For example, as we saw, %use dataframe brings in the Kotlin DataFrame library and sets up its renderer, and %use ktor-client brings in Ktor and related utilities. We maintain a list of supported libraries and their descriptors on GitHub, and many community libraries are already integrated.
  • Unintegrated libraries via Gradle syntax: If %use doesn’t support a given library, or you need to specify the version, you can still add it manually using a Gradle-style dependency block. Kotlin Notebook supports a special USE { ... } code block where you can declare repositories and dependencies, for example:
USE {

    repositories {

        maven("https://my.repo/url")

    }

    dependencies {

        implementation("com.example:my-library:1.2.3")

        implementation("org.apache.commons:commons-text:1.10.0")

    }

}


This will fetch the specified Maven artifacts and add them to the notebook’s classpath. To fine-tune how libraries are resolved, use Kotlin Notebook options.

When you use either of these methods to load a library, the Kotlin Notebook kernel may perform additional integration steps if a descriptor or integration class is present. Read more about defining your own library integration.

If you add a library in one cell, code in subsequent cells can use it, but code in the same cell may not see it until after that cell is executed. A best practice is to put your %use commands or USE {} blocks at the top of the notebook or at least in their own cells. Also, if you ever restart the kernel, you’ll need to re-run those dependency cells to re-establish the classpath.

Prototyping with project code and module dependencies

Kotlin Notebook can also interact with the code in your project, making it incredibly useful for prototyping and debugging. For example, if you have a large codebase, you can create a scratch notebook to experiment with your own APIs or data models interactively, without having to write a temporary main function or unit test.

In the 2025.1 release, using project code in notebooks has become easier, and there are more configuration options:

  • Module classpath selection: By default, when you open a notebook file in an IntelliJ IDEA project, the notebook’s classpath will not include any project dependencies. However, you can also set the notebook up to depend on all project libraries or on a particular project module with all the dependencies inside it. Switch between these options using the combobox in the notebook’s toolbar.
  • Up-to-date code: Notebooks use the compiled classes from your project. To ensure that the latest compiled .class files are available, you should build your project before running a notebook. If you edit a source file in your project while the notebook is open, a notification will remind you to rebuild the module and restart the notebook to see the changes take effect in the notebook’s output.
  • Integrations: If your project defines any integration classes for a Kotlin notebook in the module your notebook depends on, those integrations will also be loaded.

Kotlin Notebook’s approach to libraries and dependencies allows you to incorporate whatever you need – be it a well-known library or your own code – and use it interactively. Because Kotlin notebooks have access to your project code, you can do things like instantiate your application’s classes, call functions from your business logic, or run quick experiments on your data models. You can even use notebooks to write exploratory tests against your APIs, since notebooks allow you to run code in any order and inspect the results, which can be more flexible than a fixed unit test.

What’s next?

The next article will tell you about Kotlin Notebook’s advanced features. Stay tuned!

If you have any questions or suggestions, you can:

  • Ask them right under this post.
  • YouTrack: Create a #ktnb ticket to report bugs or suggest features.
  • Slack: Check out #notebooks for discussions and questions.
  • Email: Email [email protected] with any suggestions or requests for functionality that would allow you to incorporate Kotlin Notebook into your workflow.