Welcome to Livebook
Basic usage
Livebook is a tool for crafting interactive and collaborative code notebooks.
Each notebook consists of a number of cells, which serve as primary building blocks. There are Markdown cells (such as this one) that allow you to describe your work and Code cells to run your Elixir code!
To insert a new cell move your cursor between cells and click one of the revealed buttons. 👇
# This is a Code cell - as the name suggests that's where the code goes.
# To evaluate this cell, you can either press the "Evaluate" button above
# or use `Ctrl + Enter` (or Cmd + Enter on a Mac)!
message = "hey, grab yourself a cup of 🍵"
Subsequent cells have access to the bindings you’ve defined:
String.replace(message, "🍵", "☕")
Note however that bindings are not global, so each cell sees only stuff
that goes above itself. This approach helps to keep the notebook clean and
predictable as you keep working on it. Furthermore, Livebook tracks which
variables are used by each cell in order to detect which cells become
stale. For example, try changing the message
variable and you will see
the status indicator on the bottom right of the second cell become yellow.
Sections
You can leverage so called sections to nicely group related cells together. Click on the “Book” icon () in the sidebar to reveal a list of all sections. As you can see, this approach helps to easily jump around the notebook, especially once it grows.
Let’s make use of this section to see how output is captured!
cats = ~w(😼 😹 😻 😺 😸 😽)
for _ <- 1..3 do
cats
|> Enum.take_random(3)
|> Enum.join(" ")
|> IO.puts()
end
Branching sections
Additionally, you can make a section branch out from any previous regular section. Hover over the section name to reveal available actions and click on the branch icon to select the parent section.
You still have access to all the previous data:
{message, cats}
The important characteristic of a branching section is that it runs independently from other sections and as such is well suited for running long computations “in background”.
Process.sleep(300_000)
Having this cell running, feel free to insert another Code cell in the section below and see it evaluates immediately. Crashes in branched sections also have limited scope and will affect only the branched section.
Saving notebooks
By default, notebooks are stored in a temporary directory, which is fine for interactive hacking, but oftentimes you will want to save your work for later. Such can be done by clicking on the “Disk” icon () in the bottom-right corner and selecting the file location.
Once saved, you can access the location of the current .livemd
file and
its current directory using __ENV__
and __DIR__
variables:
IO.puts(__ENV__.file)
IO.puts(__DIR__)
Notebooks are stored in live markdown format, which is the Markdown you know, with just a few assumptions on how particular elements are represented. Thanks to this approach you can easily keep notebooks under version control and get readable diffs. You can also easily preview those files and even edit them in a text editor.
Keyboard shortcuts
Once you start using notebooks more, it’s gonna be beneficial to optimise how you move around. Livebook leverages the concept of navigation/insert modes and offers many shortcuts for common operations. Make sure to check out the shortcuts by clicking the “Keyboard” icon () in the sidebar or by pressing ?.
Autocompletion
Code cells also support autocompletion. Autocompletion happens automatically as you type but you can explicitly trigger it with ctrl + ␣. You must start the runtime, by executing any cell at least once, for the autocompletion engine to load.
Let’s try autocompleting the code below to System.version()
.
First put the cursor after the System
below and type .
:
System
You should have seen the editor listing many different options,
which you can use to find version
. Executing the code will
return the Elixir version.
Note you can also press tab to cycle across the completion alternatives.
Markdown extensions
Livebook also include supports for links, mathematical expressions, and Mermaid diagrams.
Links
It is possible to link between Livebooks using Markdown’s link syntax.
For example, [next chapter](chapter_2.livemd)
could be used to link
to a Livebook named chapter_2.livemd
in the same directory as the current
notebook. Once clicked, Livebook will automatically open up a new session
to execute the linked notebook.
Math expressions
Livebook uses $\TeX$ syntax for math inside your Markdown cells. It supports both inline math, like $e^{\pi i} + 1 = 0$, as well as display math:
$$ S(x) = \frac{1}{1 + e^{-x}} = \frac{e^{x}}{e^{x} + 1} $$
To write your own, put your math expressions between \$ signs for inline math or \$\$ if you want display math. You can double click the formulas above to see how they are written.
You can explore all supported expressions in the KaTeX documentation.
Mermaid diagrams
Mermaid is a library for creating diagrams
and visualizations using text and code. You can define those diagrams in
your Markdown cells via ```mermaid
blocks. Let’s see an example:
graph LR;
A-->B;
A-->C;
B-->D;
C-->D;
Elixir integration and use cases
There are many ways Elixir developers use and leverage Livebook today.
Documentation with Mix.install
Livebook is an excellent tool for documentation. Many Elixir packages use
Livebook as tutorials but you can also directly run Livebook within the context
of your existing application with the help of Mix.install/2
.
As an example, imagine you have created a notebook inside your current project,
at notebooks/example.livemd
. In order to run within the root Mix project, using
the same configuration and dependencies versions, you can change your notebook
setup cell to invoke Mix.install/2
with the following arguments:
Mix.install(
[
{:my_app, path: Path.join(__DIR__, ".."), env: :dev}
],
config_path: :my_app,
lockfile: :my_app
)
Deploying custom apps and internal tooling
Your Livebook notebooks can be deployed as actual applications which you may then share within your team and company. We have a whole guide dedicated to this topic, which is recommended reading for those who want to learn more. The next use case also builds on top of notebook deployment, let’s check it out.
Communication and automation of Elixir systems
You may also deploy notebooks as applications that automate and monitor live Elixir systems. By clicking on “+ Smart cell”, you will find Livebook provides a “Remote execution” widget, that allows you to configure the node name, cookie, and the code you want to execute on the remote node.
The node and cookie information are configured directly in the production system you want to connect to. For example, to connect to a Phoenix application running on your machine, you may start it as follows:
$ iex --sname phoenix-app --cookie secret -S mix phx.server
With this information in hand, you can query and automate tasks within existing Elixir systems. You may also mix remote execution with Livebook’s rich features to deploy applications that interact with those systems.
Debugging live systems (with attached mode)
Livebook uses the concept of a runtime, which in practice is an Elixir node responsible for evaluating your code. You can choose the runtime by clicking the “Runtime” icon () on the sidebar (or by using the s r keyboard shortcut).
By default, a new Elixir runtime is started (similarly to starting iex
)
for each notebook. You can click reconnect whenever you want to discard the
current runtime and start a new one.
You can also manually attach to an existing node by picking the “Attached Node” runtime. While in the previous section we used the “Remote execution” smart cell to connect the default Livebook runtime to an existing node, the “Attached Node” will make it so the Livebook runtime itself runs within the external node.
To do so, open up a new notebook and click the “Runtime” icon on the sidebar. Click to “Configure” the runtime and choose “Attached node”. Input the name and cookie from the remote node and you should be ready to connect to it. Once connected, be careful: any code that you execute in the notebook now runs within the connected application. You are also limited on actions you may perform. For example, you can’t install dependencies (nor would that be a good idea on a running system).
You may also connect your local Livebook instance to a node running in production depending on your platform.
Scaffolding embedded systems with Nerves
If you want to run Livebook on embedded devices, such as Raspberry Pi, BeagleBone, etc., check out the Livebook firmware built with Nerves. In such cases, Livebook uses a special runtime, called the Embedded Runtime, where all of your code runs within Livebook itself, without starting additional runtimes (which may be too expensive on limited devices).
Erlang support
Livebook also allows developers to write Erlang code. To do so, click on the submenu option on the right side of the “Elixir” cell button and choose Erlang.
Your Erlang code will run alongside your Elixir cells. This means you can leverage all of the dependency management and smart cell features outlined in the previous sections. In particular, integration between Erlang and Elixir will happen as follows:
-
Variables in Elixir are available in Erlang cells in camel-case fashion.
x
in Elixir becomesX
in Erlang.foo_bar
becomesFooBar
; -
Variables in Erlang are available in Elixir cells in underscored fashion.
X
in Erlang becomesx
in Elixir.FooBar
becomesfoo_bar
;
For example, to print all of the cats defined at the top of the notebook, but in Erlang:
[io:format("~ts", [Cat]) || Cat <- Cats].
We are just beginning the Erlang integration and contributions to further enrich it are welcome.
Evaluation vs compilation
Livebook automatically shows the execution time of each Code cell on the bottom-right of the cell. After evaluation, the total time can be seen by hovering the green dot.
However, it is important to remember that all code outside of a module in Erlang or Elixir is evaluated, and therefore executes much slower than code defined inside modules, which are compiled.
Let’s see an example. Run the cell below:
Enum.reduce(1..1_000_000, 0, fn x, acc -> x + acc end)
We are adding all of the elements in a range by iterating them
one by one. However, executing it likely takes some reasonable
amount of time, as the invocation of the Enum.reduce/3
as well
as the anonymous function argument are evaluated.
However, what if we move the above to inside a function? Let’s do that:
defmodule Bench do
def sum do
Enum.reduce(1..1_000_000, 0, fn x, acc -> x + acc end)
end
end
Now let’s try running it:
Bench.sum()
The latest cell should execute at least an order of magnitude faster
than the previous Enum.reduce/3
call. While the call Bench.sum()
itself is evaluated, the one million iterations of Enum.reduce/3
happen inside a module, which is compiled.
If a notebook is performing slower than expected, consider moving the bulk of the execution to inside modules.
Running tests
There are two main ways of running tests inside Livebook.
Doctests
Doctests allow developers to provide and test examples directly
from their documentation. Doctests are defined with the iex>
prompts under the @moduledoc
and @doc
attributes of your
modules. Let’s see an example:
defmodule MyModule do
@moduledoc """
This is an example of doctests:
iex> 2 + 2
5
iex> 6 + 7
13
"""
end
Livebook automatically detects doctests for any defined modules
and automatically executes them when you evaluate the cell.
Doctests which fail are marked in red in the gutter and show
the failure information right below them. Otherwise they are tagged
in green. For more information on doctests and their limitations,
see ExUnit.Doctest
.
ExUnit integration
It is also possible to run ExUnit
suites directly from your notebooks.
The key is to disable ExUnit
‘s autorun feature and then explicitly
run the test suite after all test cases have been defined:
ExUnit.start(autorun: false)
defmodule MyTest do
use ExUnit.Case, async: true
test "it works" do
assert true
end
end
ExUnit.run()
This is perfect for testing more complex logic that does not fit under doctests.
Next steps
That’s our quick intro to Livebook! Where to go next?
-
If you are not familiar with Elixir, there is a fast paced introduction to the language in the Distributed portals with Elixir notebook;
-
Write and deploy a chat application using Livebook;
-
Go back to the Learn page and see how to use Livebook to deploy apps, explore data, plot graphs, and much more;
-
Finally, remember Livebook is an open source project, so feel free to look into the repository to contribute, report bugs, suggest features or just skim over the codebase.
Now go ahead and build something cool! 🚢