Package Management#

Learning Objectives#

  • Understand the basics of Julia’s package management system

  • Add (install), remove, and update packages using Julia’s package manager

  • View and manage installed packages (e.g. check the status of the environment)

  • Import and use installed packages in your Julia code

  • Identify some common Julia packages and their uses and understand best practices for package management

Overview of Julia’s Package System#

Julia’s package ecosystem provides a wide range of functionality, from data manipulation and plotting to machine learning and beyond. Julia ships with a package manager called Pkg that is designed to make it easy to install and manage these packages and their dependencies.

Pkg uses a concept called environments:

  • An environment is basically a set of packages and specific versions that you have downloaded to use.

  • By default, when you use the Julia REPL or Jupyter, you’re in the “default environment”.

  • However, you can create separate environments for each project you work on, so that you only work with the packages (and versions) needed for that project. The details of the packages and versions are recorded in files Project.toml and Manifest.toml that reside in your project folder.

  • It is highly recommended that you use a separate environment for each project you work on, as this greatly enhances the reproducibility of your work.

  • For the most part, it is best not to install packages into the default environment (apart perhaps from a few select language or development tools, such as IJulia for using Julia in Jupyter notebooks).

Why use project-specific environments?

When you install packages into the default environment, you risk version conflicts between projects, as different projects may require different versions of the same package. This can lead to compatibility issues and unexpected behavior. Additionally, installing everything into the default environment makes it harder to track which packages are needed for which projects. Project-specific environments isolate dependencies, ensuring that each project has its own set of packages, which helps in avoiding these problems and makes your development process more reliable and reproducible.

The Project.toml and Manifest.toml files#

The Project.toml and Manifest.toml files enable Julia to manage and precisely specify environments.

  • The Project.toml file describes the project’s requirements at a high level. It plays an important role when developing Julia packages (which we won’t cover in this course), where it is also used to include package metadata e.g. authors, version, package compatability constraints etc. For our purposes, Project.toml just lists out the direct package dependencies for our project.

  • The Manifest.toml file records the precise state of the environment at a given time, giving a detailed snapshot of the exact versions of all packages within an environment, including their transitive dependencies. It allows us to instantiate an environment with exactly the same packages and versions that somebody else used to run their code.

Importantly, in order for someone else to run our code using the same packages and versions that we used, we just need to give them Project.toml and Manifest.toml along with our code.

Using the Pkg REPL#

The easiest way to use Pkg is through a dedicated REPL built into the Julia REPL. To access it, open the Julia REPL and then enter the ‘command’ ]:

julia> ]
(v1.11) pkg>

You can see that the prompt changes. The REPL opens in the default environment, indicated by the Julia version number (v1.11 in the above example). There is also the dedicated pkg> prompt to indicate we’re in the Pkg REPL, rather than Julia’s normal REPL.

To exit back to the regular Julia REPL, just hit backspace from within the Pkg REPL.

To see help text for using the Pkg REPL, use the help command:

(v1.11) pkg> help

Creating / activating an environment#

Creating a Pkg environment is simply a matter of:

  • Choosing a folder on our file system to associated with the environment. Typically this will be the folder where you are writing your code for some project / application. This is where the associated Project.toml and Manifest.toml files will reside.

  • Using the Pkg REPL to activate the environment (creating the Project.toml and Manifest.toml files if necessary.

Let’s suppose we have a folder MyProject where we are writing (or will write) our code. To activate an evironment within MyProject we enter the Pkg REPL and then call activate with the path to the MyProject folder (with respect to the directory where we started the Julia REPL):

julia> ]
(v1.11) pkg> activate path/to/MyProject
  Activating new project at `path/to/MyProject`

(MyProject) pkg>

Notice how the prompt now indicates we’re working with the environment MyProject.

Note: activating a new project will not yet create Project.toml and Manifest.toml - these will be created once we start adding packages.

Adding and removing packages#

To add a package to an environment to make it available to use in our code, use the add command from within the Pkg REPL. E.g. to add the latest version of the Plots.jl package to our environment:

(MyProject) pkg> add Plots

Note that we don’t include the .jl suffix!

Julia will download the package if required and then add it to the environment. It will also create / update the Project.toml and Manifest.toml files.

If we need to install a specific version, we just specify it with an @ prefix:

(MyProject) pkg> add Plots@1.40.2

To remove a package from the environment, just use the remove (or rm) command:

(MyProject) pkg> remove Plots

Note

Julia stores packages in a central ‘depot’ that is shared across environments, to optimise package management and reduce redundant downloads. When you add a package, Julia first checks this depot to see if the package (at the specific / latest version) is already available. If the package is found, it is used directly, speeding up the installation process. If the package is not found, Julia downloads it from the internet and stores it in the depot for future use. However, only the packages explicitly added to an environment are available for use within that environment.

Listing packages in the environment#

To list the packages within the environment that are direct requirements for the project (i.e. specified in Project.toml), use the status (or st) command:

(MyProject) pkg> status
Status `path/to/MyProject/Project.toml`
  [91a5bcdd] Plots v1.40.13

To list all packages in the environment (as detailed in the Manifest.toml), use the --manifest option:

(MyProject) pkg> status --manifest
Status `path/to/MyProject/Manifest.toml`
  [66dad0bd] AliasTables v1.1.3
  [d1d4a3ce] BitFlags v0.1.9
  [944b1d66] CodecZlib v0.7.8
  [35d6a980] ColorSchemes v3.29.0
  [3da002f7] ColorTypes v0.12.1
  [c3611d14] ColorVectorSpace v0.11.0
  ...
  [91a5bcdd] Plots v1.40.13
  ...
  [-- full output suppressed --]

Updating packages#

All packages#

To update all packages within the environment (i.e. all those specified in Manifest.toml), use the update (or up) command:

(MyProject) pkg> update

Julia will ensure that any version restrictions enforced by dependent packages are maintained.

Specific packages#

To update a specific package, use update with the name of the package:

(MyProject) pkg> update Plots

Again, Julia will ensure that any version restrictions enforced by dependent packages are maintained.

By default, if you specify a package Julia will only update that package, not any other packages that it may depend upon. To allow Julia to update all dependent packages as well, supply the --preserve=none option:

(MyProject) pkg> update --preserve=none Plots

Note that update is only used to install later versions. To replace a package with an older version, use add and specify the package with the version you want.

Instantiating an environment from Project.toml and Manifest.toml#

Given a folder NewProject where we already have Project.toml and Manifest.toml files, we can add all the packages specified in these files using the instantiate command. Note that we need to ensure we activate the project first:

(v1.11) pkg> activate path/to/NewProject
(NewProject) pkg> instantiate

Exercise: an environment with Plots#

  1. Create a new environment and add the Plots package to it.

  2. List all packages in environment (try with and without the --manifest option).

  3. Take a peek at the Project.toml and Manifest.toml to see the difference between these files (but don’t modify them!)

Best practices with packages#

  • Don’t modify Manifest.toml by hand! Doing so could break Julia’s package management capabilities for your project.

  • When sharing your work with others, make sure to send them the Project.toml and Manifest.toml files so that they can reproduce your environment.

  • Keep the Project.toml and Manifest.toml files under version control, to track package updates.

  • If using the Pkg API in your code, don’t use Pkg.add in performance-critical code or inside functions that run repeatedly.

  • Use using or import statements at the top of your script/notebook, to make clear what external libraries your code is using.

Julia’s Standard Library#

Julia contains a standard library of modules. These are basically just packages that ship with Julia and are ready in any environment (you don’t need to add them). There are many useful modules, here are just a small selection:

  • Pkg: for doing package management using Julia code e.g. Pkg.activate("MyProject"), Pkg.add("Plots") etc.

  • Dates: for working with dates and timestamps

  • Test: for unit testing

  • DelimitedFiles: for working with delimited files e.g. CSV.

  • LinearAlgebra: for linear algebra computations

  • Logging: for logging

See the Julia docs for more information.

Using packages in your code#

Every package defines a module of the same name (e.g. the Plots.jl pakcage defines the module Plots). Modules are Julia’s way of namespacing. To use the functionality of a package in your Julia code, you have two primary options: via using and import. They differ in how they bring names from the module into your namespace:

  • using PackageName: This brings all exported names from the PackageName module directly into your current scope, as well as PackageName itself. You can call those names without qualifying them by the module name. (You can still use the module to qualify the names if you like e.g. PackageName.do_something()

  • import PackageName: This makes the module PackageName available, but does not pull any of its names into your scope. You must qualify everything with the module’s name.

For example, If you wanted to use the Julia standard library Dates module, the two approaches would be:

# Import Dates and call `today` function
import Dates

Dates.today()
2025-06-07
# Using Dates and call `today` function
using Dates

today()  # or Dates.today()
2025-06-07

Exercise: using Plots#

The plot function from the Plots.jl can be used to plot a line graph:

# TODO: what to write here to make the plotting code work?

# Plot y = x^3
x = range(-1, 1; step=0.01)
y = x .^ 3
Plots.plot(x, y)

Complete the code above so that it runs. How could you modify the code so that we call plot instead of Plots.plot?

Overview of Common 3rd party Packages in Julia#

Julia has a rich ecosystem of packages that cater to various needs such as data manipulation, visualisation, scientific computing, and more. Below is an overview of some commonly used packages along with links to detailed resources for each package.

StaticArrays.jl#

StaticArrays.jl provides stack-allocated, fixed-size arrays optimised for ultra-fast small-matrix and vector computations.

StaticArrays.jl

DifferentialEquations.jl#

DifferentialEquations.jl provides a unified framework providing best-in-class, high-performance solvers for ODEs, SDEs, DAEs, and PDEs.

DifferentialEquations.jl

DataFrames.jl#

DataFrames.jl provides tools for working with tabular data, similar to pandas in Python or data.frame in R. It is essential for data manipulation and analysis.

DataFrames.jl

Plots.jl#

Plots.jl is a powerful and flexible plotting package in Julia. It supports multiple backends and is widely used for creating a variety of visualisations.

Plots.jl

CSV.jl#

CSV.jl is a fast and reliable package for reading and writing CSV files. It integrates seamlessly with DataFrames.jl for handling tabular data.

CSV.jl

JuMP.jl#

JuMP.jl is a domain-specific modelling language for mathematical optimisation embedded in Julia. It is used for linear programming, non-linear programming, and other optimisation problems.

JuMP.jl

Distributions.jl#

Distributions.jl provides a large collection of probability distributions and related functions. It is useful for statistical modelling and probabilistic computations.

Distributions.jl

Flux.jl#

Flux.jl is a machine learning library in Julia. It is designed to be easy to use while being highly extensible, providing tools for building and training neural networks.

Flux.jl

Makie.jl#

Makie.jl is a high-performance plotting library for data visualisation. It provides a powerful and flexible interface for creating complex visualisations.

Makie.jl

HTTP.jl#

HTTP.jl is a package for handling HTTP requests and responses. It is useful for web development, API interactions, and network programming.

HTTP.jl

Gadfly.jl#

Gadfly.jl is a plotting and data visualisation system inspired by ggplot2 in R. It is great for creating complex, aesthetically pleasing plots.

Gadfly.jl

By using the above links, you can explore more about each package and learn how to effectively use them in Julia.

Exercise: Exploring Julia Packages#

Julia has a rich ecosystem of packages that support a wide range of tasks. Now it’s your turn to explore one of these packages and see how it might fit into your own workflows or projects.

  • Choose one package from the list above that aligns with your interests or the kind of work you expect to do after this course (e.g. data analysis, visualisation, optimisation, scientific computing, etc.).

  • Create an environment and install the package into it.

  • Try a simple example using the package:

    • For plotting packages, create a basic plot (e.g. line plot, scatter plot).

    • For data packages, load or create a small dataset and perform a basic manipulation or analysis.

End of Section Quiz#

What is the correct way to add the Plots package in Julia?

Why should you consider using Pkg.activate("MyProject") before installing packages?