Julia has a built-in package manager called Pkg that provides sophisticated dependency management out of the box.
The manifest file that specifies your project's direct dependencies:
name = "MyProject"
uuid = "12345678-1234-1234-1234-123456789abc"
version = "0.1.0"
[deps]
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
[compat]
DataFrames = "1.3"
Plots = "1.25"
julia = "1.6"- Lists direct dependencies with their UUIDs
[compat]section specifies version requirements- Human-readable and version-controlled
The lock file that captures the entire dependency graph with exact versions:
[[DataFrames]]
deps = ["Compat", "DataAPI", "Tables"]
uuid = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
version = "1.3.4"
[[Tables]]
deps = ["DataAPI"]
uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"
version = "1.7.0"- Auto-generated, should not be edited manually
- Ensures reproducible environments
- Includes all transitive dependencies with exact versions
REPL mode (press ] to enter):
add DataFrames # Add a package
add DataFrames@1.3 # Add specific version
rm DataFrames # Remove a package
update # Update all packages
status # List installed packagesScript mode:
using Pkg
Pkg.add("DataFrames")
Pkg.instantiate() # Install from Manifest.tomlJulia supports isolated environments similar to Python's virtual environments:
# Create a new project
Pkg.activate("path/to/project")
Pkg.add("DataFrames")This creates Project.toml and Manifest.toml in the project directory.
Pkg.activate() # Switch to default environmentThe default environment is located at ~/.julia/environments/v1.x/.
Julia's package manager uses a sophisticated resolver that:
- Handles semantic versioning automatically
- Resolves version conflicts across the dependency tree
- Finds compatible versions of all packages
- Updates
Manifest.tomlwith resolved versions
The [compat] section uses standard version specifiers:
[compat]
DataFrames = "1.3" # >=1.3.0, <2.0.0
Plots = "1.25.0 - 1.30.0" # Range
CSV = "^0.10" # Caret (>=0.10.0, <0.11.0)Julia packages are published to registries (default: General Registry):
- Packages are identified by name and UUID
- UUIDs prevent naming conflicts
- Multiple registries can be used simultaneously
# From GitHub
Pkg.add(url="https://github.com/user/Package.jl")
# From local path
Pkg.develop(path="path/to/Package")Pkg.develop("MyPackage") # Clone package for local development
Pkg.free("MyPackage") # Return to using registry versionPkg.generate("MyPackage")Creates a package structure with Project.toml, src/, and test/.
- Automatic Dependency Resolution: No need for separate tools like pip-tools or Poetry
- Reproducible Environments:
Manifest.tomlensures exact version reconstruction - UUID-based Identification: Prevents naming conflicts
- Built-in: No external tools required
- Per-Project Isolation: Easy environment switching
- Precompilation: Packages are precompiled for faster loading
- Commit both files: Version control both
Project.tomlandManifest.toml - Use
[compat]: Specify compatibility bounds to avoid breaking changes - Run
Pkg.instantiate(): On new machines to recreate exact environment - Separate environments: Use project-specific environments, not the global one
- Test compatibility: Run
Pkg.test()to verify package functionality
Key Difference from Python: Julia's dependency management is fully integrated into the language from the start, providing a unified experience without needing third-party tools like Poetry, Pipenv, or conda.