Table of contents
- startup.jl
- OhMyREPL
- Revise.jl
- Infiltrator
- PrecompileTools
- BenchmarkTools
- Cthulhu
- ReTest and InlineTests
- PkgTemplates
- JET
- LiveServer
- Comonicon
- Conclusion
Julia is a high-performance, dynamic programming language designed for technical computing and data science. The language offers a flexible and expressive syntax, and also delivers the performance benefits of compiled languages like C++. Like Python, Julia also offers an interactive REPL (Read-Eval-Print Loop) environment for real-time data exploration and rapid prototyping.
If you are fairly new to Julia, here are a few things you might want to know to improve your developer experience.
startup.jl
Every time you start Julia, it looks for a file named startup.jl in a config directory.
| Operating System | startup.jl Location |
|---|---|
| Windows | C:\Users\USERNAME\.julia\config\startup.jl |
| macOS | /Users/USERNAME/.julia/config/startup.jl |
| Linux | /home/USERNAME/.julia/config/startup.jl |
This file is executed before the REPL starts, allowing you to customize your Julia environment.
For example, if you added the following code to your startup.jl, it would ensure that Revise,
OhMyREPL and BenchmarkTools are always installed whenever you start Julia.
# Setup OhMyREPL and Reviseimport Pkglet pkgs = ["Revise", "OhMyREPL", "BenchmarkTools"] for pkg in pkgs if Base.find_package(pkg) === nothing Pkg.add(pkg) end endendThis thread on the JuliaLang Discourse
has some neat examples of things you may want to add to your startup.jl.
If you wish to go one step further, you can create a Julia package called
Startup.jl, place it anywhere on your computer and load it
in startup.jl using the following code:
if Base.isinteractive() push!(LOAD_PATH, joinpath(ENV["HOME"], "gitrepos", "Startup.jl")) using StartupendThe advantage of this approach is that the contents of Startup.jl can be precompiled and your
Julia REPL starts up very quickly.
With the Startup.jl package approach, your root environment can be empty and you can still use
functionality exposed by Startup.jl:

OhMyREPL
OhMyREPL.jl is a package that provides syntax
highlighting, bracket highlighting, rainbow brackets, and more for the Julia REPL. Once installed,
it can enhance your REPL experience dramatically, making it more visually appealing and easier to
work with.


Revise.jl
Revise.jl is a game-changer for Julia development. It
automatically reloads modified source files without restarting the Julia session. This makes
iterative development much smoother.
Once set up, any changes you make to your code files are immediately available in your active Julia session.
Revise can "track" changes in single files if you include them using includet:

If you want Revise to track changes in a package you are developing locally, simply run
using Revise before you load the package for the first time.
See Revise's documentation for how to set this
up to happen automatically all the time by adding setup code to your startup.jl file.
One of the issues with Revise is that it cannot deal with changes in struct. Let's say I wanted
to make a change like this:
struct Foo x::Int y::Float64endRevise throws an error and warning because it is unable to make that change; and Revise changes
the color of the Julia prompt:

There are some workarounds for this but
the easiest thing to do is to restart the Julia session after you are make changes to any
struct.
Infiltrator
Infiltrator.jl is a debugger and code inspection
tool for Julia. It allows you to insert breakpoints in your code and inspect the current scope's
variables.
When Julia hits the @infiltrate macro, it'll pause execution, and drop you into a Julia REPL that
allows you to inspect the current scope.

You can also use @infiltrate i == 3 and that'll drop you into a Julia REPL only in the third
iteration of the for loop.
When using @infiltrate conditional_expression with Revise, you can jump into any function at any
point of the execution to inspect values of variables in a Julia REPL. You can even load additional
packages like DataFrames or Plots to explore your data in the scope of any function
interactively while debugging. This combination can make for a versatile and productive debugging
experience.
PrecompileTools
PrecompileTools is a package that allows package developers to specify which parts of the package should be precompiled. From the official documentation:
PrecompileToolscan force precompilation of specific workloads; particularly with Julia 1.9 and higher, the precompiled code can be saved to disk, so that it doesn't need to be compiled freshly in each Julia session. You can usePrecompileToolsas a package developer, to reduce the latency experienced by users of your package for "typical" workloads; you can also usePrecompileToolsas a user, creating custom "Startup" package(s) that precompile workloads important for your work.
Precompiling Julia packages can significantly reduce the loading times for you and your users, providing a much more responsive experience.
For example, I have the following in my Startup.jl to reduce Julia REPL startup times:
module Startup
using PrecompileTools
@setup_workload begin @compile_workload begin using Pkg using Revise using OhMyREPL endend
endBenchmarkTools
BenchmarkTools.jl is an essential package to help quantify the performance of your code. It provides utilities to benchmark code snippets, giving insights into their run-time and memory allocations.
The @benchmark macro runs a number of trials of a function and plots a histogram in the terminal
showing what kind of performance you are getting out of that particular function. As an example, we
can compare the performance of a custom sum function without and with the @simd macro:


Cthulhu
Delving deep into Julia's compiler optimizations and type inference can sometimes feel daunting and
that's where Cthulhu.jl comes to the rescue. Cthulhu
is an interactive terminal user interface that is an alternative to @code_lowered and
@code_typed, and allows developers to interactively "descend" into the lowered and optimized
versions of their Julia code, making it easier to debug performance issues and understand how
Julia's JIT compiler optimizes code.
For example, if we examine the mysum function from the previous section, we can see that a is
being inferred as a Int64 or a Float64, i.e. Union{Float64, Int64}.

In this particular case, by changing a = 0 to a = 0.0, we can make the code generated by Julia
more optimized, i.e. a is now being inferred only as a Float64.

Here's the benchmark results with a = 0 (left) and a = 0.0 (right), with the latter being almost
3 times faster.


ReTest and InlineTests
Julia has a built-in package Test for unit testing. This requires writing tests in a separate
folder, i.e. in test/runtests.jl; and these tests are run in a separate process when you can
Pkg.test(). There's also no out of the box solution to run a subset of tests.
Using InlineTests allows you to write tests directly in your source files, and you can also choose
to run a subset of tests. If you choose to run it with retest, you can make changes that are
tracked with Revise, allowing faster iteration using a test driven development workflow.
In the screenshot below, I have shown an example of having a @testset as part of the package
itself, i.e. in ./src/layout.jl:

You'll also notice from the screenshot that ReTest contains a function called retest which
allows running a subset of tests by passing in a pattern as the second argument.
PkgTemplates
Julia has a built-in way to create a new package, using Pkg.generate(). However,
PkgTemplates.jl is a package that makes the process
of creating new packages as easy and customizable at the same time. PkgTemplates can generate new
Julia packages with numerous features out-of-the-box that follow best practices (e.g. GitHub
Actions, Documenter, etc).
Creating a new package then becomes as straightforward as running the following:
using PkgTemplatest = Template()t("MyNewPackage")You can customize the template too:
using PkgTemplatest = Template( dir = "~/gitrepos/", julia = v"1.10", plugins = [ Git(; ssh = true, manifest = true), GitHubActions(), Documenter{GitHubActions}(), ],)t("MyNewPackage")JET
JET.jl is a powerful static code analyzer tailored for the
Julia programming language. JET serves as a "linter" – identifying potential runtime errors
without actually executing the code. It works by simulating the Julia compiler's type inference
process.
fib(n) = n ≤ 2 ? n : fib(n-1) + fib(n-2)
fib(1000) # => never terminatesfib(m) # => ERROR: UndefVarError: `m` not definedfib("1000") # => ERROR: MethodError: no method matching isless(::String, ::Int64)You can see the other kinds of warnings that JET can produce in the
demo.jl file.
LiveServer
LiveServer.jl allows developers to serve static sites
locally and refreshes your browser automatically as you edit source files. You can even use it to
view or update documentation.
# serve contents of any folderLiveServer.serve(; dir, launch_browser = true)
# serve documentation of any packagePkg.activate("./docs")LiveServer.servedocs(; launch_browser = true)Comonicon
Comonicon.jl is a rich tool for building command-line applications. Comonicon allows you to easily convert your Julia scripts and packages into command-line tools with minimal effort.
Using Comonicon, you can:
- Parse command-line arguments
- Generate help messages
- Handle subcommands
- And more
For example, I've added into my
Startup.jl/src/jl.jl
some helper subcommands that I can access from that command line in any folder.

Conclusion
Julia's ecosystem is filled with tools designed to optimize the developer's workflow, making it easier and more efficient to write, test, and deploy code.