
Typix
Typix aims to make it easier to use Nix in Typst projects.
- Dependency management: supports arbitrary dependencies including fonts, images, and data
- Reproducible: via a hermetically sealed build environment
- Extensible: full support for Typst packages
Features
- Automatically fetch dependencies and compile in a single command (
nix run .#build
) - Watch input files and recompile on changes (
nix run .#watch
) - Set up a shell environment with all dependencies made available via environment variables and symlinks
- Extensible via
mkTypstDerivation
- Support for dependencies such as fonts, images, and data
- Typst packages fetched from the official Typst packages CDN
Getting Started
After installing Nix and enabling flakes, you can initialize a flake from the default template:
nix flake init --refresh -t github:loqusion/typix
Alternatively, you can use a template demonstrating Typst packages usage:
nix flake init --refresh -t 'github:loqusion/typix#with-typst-packages'
Here are some commands you can run from any template:
nix run .#watch
— watch the input files and recompile on changesnix run .#build
— compile and copy the output to the current directory
For more information, check out the docs.
Getting Started
First, install Nix:
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install
Make sure nix-command
and flakes
are enabled:
~/.config/nix/nix.conf
experimental-features = nix-command flakes
Finally, you can initialize a flake from the default template:
nix flake init --refresh -t github:loqusion/typix
Alternatively, you can use a template demonstrating Typst packages usage:
nix flake init --refresh -t 'github:loqusion/typix#with-typst-packages'
Here are some commands you can run from any template:
nix run .#watch
— watch the input files and recompile on changesnix run .#build
— compile and copy the output to the current directory
For more info, see nix run --help
.
Adding dependencies
You can add dependencies to your flake inputs1 so that Typst compilation does not depend on the transient state of the local system: instead, any dependencies are automatically fetched and made available in a sandboxed environment.
Examples of dependencies you might want to add:
- Font files —
fontPaths
- Image files —
virtualPaths
- Data files (e.g. JSON,
TOML, XML) —
virtualPaths
For a more complete description of how to specify flake inputs, see the Nix Reference Manual section on flakerefs.
See also: https://zero-to-nix.com/concepts/flakes
nixpkgs
Many popular fonts are available as packages to nixpkgs, so if you're wanting to add a font it's good to try that before anything else.
To determine the path(s) to the files you wish to include, first run the
following command (which creates a symbolic link named result
in the current
directory):
nix-build '<nixpkgs>' --out-link result --attr PACKAGE_NAME
Then explore the result
with whichever commands you like — for instance, using
unix-tree
:
tree ./result
result
└── share
└── fonts
└── truetype
├── Roboto-BlackItalic.ttf
├── Roboto-Black.ttf
├── Roboto-BoldItalic.ttf
├── Roboto-Bold.ttf
├── RobotoCondensed-BoldItalic.ttf
├── RobotoCondensed-Bold.ttf
├── RobotoCondensed-Italic.ttf
├── RobotoCondensed-LightItalic.ttf
├── RobotoCondensed-Light.ttf
├── RobotoCondensed-MediumItalic.ttf
├── RobotoCondensed-Medium.ttf
├── RobotoCondensed-Regular.ttf
├── Roboto-Italic.ttf
├── Roboto-LightItalic.ttf
├── Roboto-Light.ttf
├── Roboto-MediumItalic.ttf
├── Roboto-Medium.ttf
├── Roboto-Regular.ttf
├── Roboto-ThinItalic.ttf
└── Roboto-Thin.ttf
Here, we can see that the relative path should be share/fonts/truetype
, so in
flake.nix
we use that information like so:
{
outputs = { nixpkgs, typix }: let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
in {
packages.${system}.default = typix.lib.${system}.mkTypstDerivation {
fontPaths = [
"${pkgs.roboto}/share/fonts/truetype"
];
};
};
}
GitHub
GitHub hosts a great deal of fonts and icon libraries, and Nix makes it easy to add GitHub repositories as flake inputs with URL-like syntax.
Here's an example of specifying a GitHub URL as a flake input and adding it to
virtualPaths
, specifying
that we want the svgs/regular
directory to be accessible from icons
:
{
inputs = {
font-awesome = {
url = "github:FortAwesome/Font-Awesome";
flake = false;
};
};
outputs = { typix, font-awesome }: let
system = "x86_64-linux";
in {
packages.${system}.default = typix.lib.${system}.mkTypstDerivation {
virtualPaths = [
{
dest = "icons";
src = "${font-awesome}/svgs/regular";
}
];
};
};
}
With this, we can use it in Typst as if it were any other local path:
#image("icons/heart.svg")
Using local files
If all else fails, you can always manually download what you need and move it to your Typst project directory.
Here's what you need to know:
- The Typst compiler invoked by
buildTypstProject
,buildTypstProjectLocal
, etc. won't see the files you've added unless they're present in one of the source tree parameters — in practice, these aresrc
,fontPaths
, andvirtualPaths
. (This doesn't apply towatchTypstProject
.) - Paths to font files must still be passed in
fontPaths
or otherwise made known to the Typst compiler (e.g. via--font-path
).
See "Specifying sources" for information on how to expand a source tree to include the files you need.
Specifying sources
A number of derivations in Typix accept source trees as parameters, such as
src
,
fontPaths
, and
virtualPaths
. Specifying
these is usually as simple as
cleanTypstSource
in the case of
src
and string interpolation (via ${...}
) in the case of fontPaths
and
virtualPaths
, but there are situations where more is required or desirable.
Expanding a source tree
TL;DR: you can use
lib.sources.cleanSource
, but the problem with this approach is that every change to a file tracked by git will invalidate the cache and trigger a rebuild.
To include more local files1 in a source tree, you can use a
combination of different functions in lib.fileset
such as lib.fileset.unions
,
lib.fileset.fromSource
, and
lib.fileset.toSource
, like so:
{
outputs = { nixpkgs, typix }: let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
inherit (pkgs) lib;
typixLib = typix.lib.${system};
myTypstSource = typixLib.cleanTypstSource ./.;
in {
packages.${system}.default = typixLib.mkTypstDerivation {
src = lib.fileset.toSource {
root = ./.;
fileset = lib.fileset.unions [
(lib.fileset.fromSource myTypstSource)
./path.svg
./other/path.svg
./another
];
};
};
};
}
This will create a source tree that looks something like:
/nix/store/...
├── another
│ ├── path1.svg
│ ├── path2.svg
│ └── path3.svg
├── path.svg
├── other
│ └── path.svg
└── ...
lib.fileset
functions can only be used with local files, not
e.g. flake inputs, which is what
virtualPaths
is for.
Source filtering
You can do source filtering primarily using
builtins.filterSource
and functions in
lib.sources
such as
lib.sources.cleanSourceWith
.
A more detailed explanation can be found in the Nix discussion: "Filtering Source Trees with Nix and Nixpkgs".
Here's an example which picks specific files by name:
{
outputs = { nixpkgs, typix, font-awesome }: let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
fontAwesomeSubset = let
icons = [
"gem.svg"
"heart.svg"
"lightbulb.svg"
];
in lib.sources.cleanSourceWith {
src = "${font-awesome}/svgs/regular";
filter = path: type:
builtins.any (icon: builtins.baseNameOf path == icon) icons;
};
in {
packages.${system}.default = typix.lib.${system}.mkTypstDerivation {
virtualPaths = [
fontAwesomeSubset
];
};
};
}
Declaring a shell environment
You can automatically pull your project's dependencies into your shell by
declaring a shell environment and then activating
it with nix develop
or direnv
.
Here's an example in a flake using Typix's
devShell
:
{
outputs = { typix }: let
system = "x86_64-linux";
typixLib = typix.lib.${system};
watch-script = typixLib.watchTypstProject {/* ... */};
in {
# packages, apps, etc. omitted
devShells.${system}.default = typixLib.devShell {
fontPaths = [/* ... */];
virtualPaths = [/* ... */];
packages = [
watch-script
];
};
};
}
What this example does:
- Fonts added to
fontPaths
will be made available totypst
commands via theTYPST_FONT_PATHS
environment variable. - Files in
virtualPaths
will be recursively symlinked to the current directory (only overwriting existing files whenforceVirtualPaths
istrue
). - For convenience, the
typst-watch
script is added, which will runwatchTypstProject
.
Using Typst packages
TL;DR: Use this example as a template:
nix flake init --refresh -t 'github:loqusion/typix#with-typst-packages'
Typst packages are considered experimental at the time of writing, and the methods documented here may become outdated at any point if breaking changes are made upstream.
If you experience any unexpected errors or bugs, and there are no open issues related to your problem, feel free to open an issue.
There are two types of Typst packages: published and unpublished:
- Published packages are those submitted to the Typst Packages repository and can be browsed on Typst Universe.
- Unpublished packages are packages that are only available from unofficial sources. They can be stored locally on your system, on a GitHub repository, or elsewhere. ("Unpublished" can also refer to unpublished versions of a package which has published versions.)
Transitive dependencies — that is, a dependency's dependencies — must be
added explicitly, in addition to any direct dependencies you have. For
instance, cetz
0.3.4 depends on oxifmt
0.2.1, so if you use cetz
0.3.4 you
must also ensure oxifmt
0.2.1 is provided. This applies recursively: if you
depend on A
which depends on B
and B
depends on C
, you must explicitly
specify both B
and C
, in addition to A
. Also, the precise version is
important: if different versions of the same package are imported, both
versions must be specified.
The method to add Typst packages differs depending on whether they are published or unpublished.
Published Typst packages
Published Typst packages work out of the box for for watchTypstProject
and
commands executed while devShell
is active.
For buildTypstProject
, buildTypstProjectLocal
, and mkTypstDerivation
,
there are two methods:
unstable_typstPackages
(recommended)TYPST_PACKAGE_CACHE_PATH
It is recommended to use unstable_typstPackages
, as it is faster and consumes
less disk space.
The unstable_typstPackages
attribute
The unstable_typstPackages
attribute is used to fetch packages from the official
Typst packages CDN at https://packages.typst.org
.
For more information, see the respective documentation for the attribute on
buildTypstProject
, buildTypstProjectLocal
, and mkTypstDerivation
.
{
outputs = {
nixpkgs,
typix,
}: let
inherit (nixpkgs) lib;
system = "x86_64-linux";
unstable_typstPackages = [
{
name = "cetz";
version = "0.3.4";
hash = "sha256-5w3UYRUSdi4hCvAjrp9HslzrUw7BhgDdeCiDRHGvqd4=";
}
# Transitive dependencies must be manually specified
# `oxifmt` is required by `cetz`
{
name = "oxifmt";
version = "0.2.1";
hash = "sha256-8PNPa9TGFybMZ1uuJwb5ET0WGIInmIgg8h24BmdfxlU=";
}
];
build-drv = typix.lib.${system}.buildTypstProject {
inherit unstable_typstPackages;
# ...
};
build-script = typix.lib.${system}.buildTypstProjectLocal {
inherit unstable_typstPackages;
# ...
};
in {
packages.${system}.default = build-drv;
apps.${system}.default = {
type = "app";
program = lib.getExe build-script;
};
};
}
The TYPST_PACKAGE_CACHE_PATH
environment variable
This method downloads the entire contents of the Typst Packages repository, making all packages available in your Typst project.
First, add the repository to flake inputs:
{
inputs.typst-packages = {
url = "github:typst/packages";
flake = false;
};
}
Then, use it in flake outputs:
{
outputs = {
nixpkgs,
typix,
typst-packages,
}: let
inherit (nixpkgs) lib;
system = "x86_64-linux";
build-drv = typix.lib.${system}.buildTypstProject {
TYPST_PACKAGE_CACHE_PATH = "${typst-packages}/packages";
# ...
};
build-script = typix.lib.${system}.buildTypstProjectLocal {
TYPST_PACKAGE_CACHE_PATH = "${typst-packages}/packages";
# ...
};
in {
packages.${system}.default = build-drv;
apps.${system}.default = {
type = "app";
program = lib.getExe build-script;
};
};
}
Unpublished Typst packages
If the Typst package you want to use is stored locally — in the same repository as your flake — all you have to do is directly import the entrypoint module:
#import "my-typst-package/src/lib.typ": my-item
#my-item
You may want to expand the source tree or filter certain files.
If the imported module imports any packages, those packages must be specified using one of the methods documented in this chapter.
If you need to fetch an unpublished Typst package from a GitHub repository instead, see below.
Fetching from a GitHub repository
You can use this example as a template:
nix flake init --refresh -t 'github:loqusion/typix#with-typst-packages-unpublished'
Add the GitHub repository containing the unpublished Typst package to flake inputs:
{
inputs = {
my-typst-package = {
url = "github:loqusion/my-typst-package";
flake = false;
};
};
}
Then, create a derivation containing the inputs and pass it to Typst with
the TYPST_PACKAGE_PATH
environment variable:
{
outputs = {
nixpkgs,
typix,
my-typst-package,
}: let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
inherit (pkgs) lib;
inherit (lib.strings) escapeShellArg;
mkTypstPackagesDrv = name: entries: let
linkFarmEntries =
lib.foldl (set: {
name,
version,
namespace,
input,
}:
set
// {
"${namespace}/${name}/${version}" = input;
})
{}
entries;
in
pkgs.linkFarm name linkFarmEntries;
unpublishedTypstPackages = mkTypstPackagesDrv "unpublished-typst-packages" [
# Unpublished packages can be added here
{
name = "my-typst-package";
version = "0.1.0";
namespace = "local";
input = my-typst-package;
}
];
# Any transitive dependencies on published packages must be added here
unstable_typstPackages = [
{
name = "oxifmt";
version = "0.2.1";
hash = "sha256-8PNPa9TGFybMZ1uuJwb5ET0WGIInmIgg8h24BmdfxlU=";
}
];
build-drv = typix.lib.${system}.buildTypstProject {
inherit unstable_typstPackages;
TYPST_PACKAGE_PATH = unpublishedTypstPackages;
# ...
};
build-script = typix.lib.${system}.buildTypstProjectLocal {
inherit unstable_typstPackages;
TYPST_PACKAGE_PATH = unpublishedTypstPackages;
# ...
};
watch-script = typix.lib.${system}.watchTypstProject {
# `watchTypstProject` can already access published packages, so
# `unstable_typstPackages` is not needed here
typstWatchCommand = "TYPST_PACKAGE_PATH=${escapeShellArg unpublishedTypstPackages} typst watch";
# ...
};
in {
packages.${system}.default = build-drv;
apps.${system}.default = {
type = "app";
program = lib.getExe build-script;
};
apps.${system}.watch = {
type = "app";
program = lib.getExe watch-script;
};
};
}
Finally, you can use the package in a Typst file:
#import "@local/my-typst-package:0.1.0": *
#nothing
Derivations
As paraphrased from the Nix Reference Manual:
A derivation is a specification for running an executable on precisely defined input files to repeatably produce output files at uniquely determined file system paths.
The derivation constructors defined in Typix extend this behavior by running
typst compile
/typst watch
in a context where all the dependencies of your
Typst project (fonts, images, etc.) will be made available to the Typst
compiler, regardless of if they're already present on the system it runs on.
buildTypstProjectLocal
— Returns a derivation for compiling a Typst project and copying the output to the current directory.buildTypstProject
— Returns a derivation for compiling a Typst project.devShell
— Sets up a shell environment that activates withnix develop
ordirenv
.mkTypstDerivation
— A generic derivation constructor for running Typst commands.watchTypstDerivation
— Returns a derivation for a script that watches an input file and recompiles on changes.
buildTypstProject
Returns a derivation for compiling a Typst project.
If you want to build to the project directory, use
buildTypstProjectLocal
instead.
Parameters
All parameters accepted by
mkTypstDerivation
are also accepted by
buildTypstProject
. They are repeated below for convenience.
src
Source containing all local files needed in your Typst project.
emojiFont
optional
Specify which emoji font to use. If emojiFont
is null
, no emoji font will
be included.
May be any of the following:
"twemoji"
(default)"twemoji-cbdt"
"noto"
"noto-monochrome"
"emojione"
null
— Don't include any emoji font (e.g. so you can include your own)
Note about difference between "twemoji"
and "twemoji-cbdt"
The default Twemoji font displays color emojis using the SVG font format,
which may not be supported by some systems. If emojis aren't displaying
properly, using "twemoji-cbdt"
may fix it.
fontPaths
optional
List of sources specifying paths to font files that will be made available to your Typst project. With this, you can compile Typst projects even when the fonts it uses are not available on your system.
Used for setting TYPST_FONT_PATHS
(see text#font
).
Example
{
outputs = { nixpkgs, typix }: let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
in {
packages.${system}.default = typix.lib.${system}.buildTypstProject {
fontPaths = [
"${pkgs.roboto}/share/fonts/truetype"
];
};
};
}
installPhaseCommand
optional
Command (or commands) to run during
installPhase
.
typstCompileCommand
optional
Base Typst command to run to compile the project. Other arguments will be appended based on the parameters you supply.
Default is typst compile
.
typstOpts
optional
Attrset specifying command-line options to pass to the typst
command.
These are in addition to any options you manually pass in
typstCompileCommand
.
Default:
{
format = "pdf";
}
Example
{
format = "png";
ppi = 300;
}
...will result in a command like:
typst compile --format png --ppi 300 <source> <output>
typstSource
optional
Typst input file to compile.
Default is main.typ
.
unstable_typstPackages
optional
This is an unstable feature. Its API does not follow Semantic Versioning, and derivations relying on this feature may break at any time, even if you don't update Typst or Typix.
When this feature reaches stability, it will be renamed to typstPackages
.
(The old name will be kept as an undocumented alias, to avoid unnecessary
breakage.)
List of Typst packages to use in your Typst project, fetched from the
official Typst packages CDN at https://packages.typst.org
.
Each element of the list is an attribute set with the following keys:
name
: the package's identifier in its namespaceversion
: the package's version as a full major-minor-patch triplenamespace
(optional): the package's namespace (defaults topreview
)hash
: hash of the downloaded package tarball
hash
must be manually updated to match the hash of the package tarball downloaded
from the registry, using the "fake hash method". See Updating source hashes
for how to do this.
Sometimes, you might encounter a Typst compilation error that looks like this:
> help: error occurred while importing this module
> ┌─ @preview/cetz:0.3.4/src/canvas.typ:3:8
> │
> 3 │ #import "util.typ"
> │ ^^^^^^^^^^
> help: error occurred while importing this module
> ┌─ @preview/cetz:0.3.4/src/lib.typ:3:8
> │
> 3 │ #import "canvas.typ": canvas
> │ ^^^^^^^^^^^^
> help: error occurred while importing this module
> ┌─ main.typ:1:8
> │
> 1 │ #import "@preview/cetz:0.3.4"
> │ ^^^^^^^^^^^^^^^^^^^^^
>
For full logs, run 'nix log /nix/store/6jhjxbl7glmy4adpr5wzfgn9jvsyyipf-typst.drv'.
In this example, Nix is hiding too much output for us to diagnose the issue.
Run the command again with the -L
flag (in our case, nix run .#build -L
):
> downloading @preview/oxifmt:0.2.1
> error: failed to download package (Network Error: OpenSSL error)
> ┌─ @preview/cetz:0.3.4/src/deps.typ:1:8
> │
> 1 │ #import "@preview/oxifmt:0.2.1"
> │ ^^^^^^^^^^^^^^^^^^^^^^^
> help: error occurred while importing this module
> ┌─ @preview/cetz:0.3.4/src/util.typ:1:8
> │
> 1 │ #import "deps.typ"
> │ ^^^^^^^^^^
> help: error occurred while importing this module
> ┌─ @preview/cetz:0.3.4/src/canvas.typ:3:8
> │
> 3 │ #import "util.typ"
> │ ^^^^^^^^^^
> help: error occurred while importing this module
> ┌─ @preview/cetz:0.3.4/src/lib.typ:3:8
> │
> 3 │ #import "canvas.typ": canvas
> │ ^^^^^^^^^^^^
> help: error occurred while importing this module
> ┌─ main.typ:1:8
> │
> 1 │ #import "@preview/cetz:0.3.4"
> │ ^^^^^^^^^^^^^^^^^^^^^
We can see that cetz
is trying to import oxifmt
0.2.1, but Typst can't
download it because Nix derivations are (by design) run in an environment
which does not support networking. To fix this, add oxifmt
0.2.1 to
unstable_typstPackages
alongside your direct dependencies.
(Make sure to match the exact version shown in your error message!!)
There is currently no official support for unpublished Typst packages. However, there is a workaround.
Example
{
outputs = { typix }: let
system = "x86_64-linux";
in {
packages.${system}.default = typix.lib.${system}.buildTypstProject {
unstable_typstPackages = [
{
name = "cetz";
version = "0.3.4";
hash = "sha256-5w3UYRUSdi4hCvAjrp9HslzrUw7BhgDdeCiDRHGvqd4=";
}
# Transitive dependencies must be manually specified
# `oxifmt` is required by `cetz`
{
name = "oxifmt";
version = "0.2.1";
hash = "sha256-8PNPa9TGFybMZ1uuJwb5ET0WGIInmIgg8h24BmdfxlU=";
}
];
};
};
}
Then you can import and use the package in Typst:
#import "@preview/cetz:0.3.4"
#cetz.canvas({
import cetz.draw: *
circle((0, 0))
line((0, 0), (2, 1))
})
virtualPaths
optional
List of sources that will be made virtually available to your Typst project. Useful for projects which rely on remote resources, such as images or data.
Each element of the list is an attribute set with the following keys:
src
: path to source file or directorydest
(optional): path where file(s) will be made available (defaults to.
)- If
src
is a directory,dest
will be a directory containing the files in that directory.- Specifying the same
dest
for multiplesrc
directories will merge them.
- Specifying the same
- If
src
is a file,dest
will be a copy of that file.
- If
Instead of an attrset, you may use a path which will be interpreted the same as
if you had specified an attrset with just src
.
Example
You can specify dependencies in your flake input, and then use them in your project with something like:
{
inputs = {
font-awesome = {
url = "github:FortAwesome/Font-Awesome";
flake = false;
};
};
outputs = { typix, font-awesome }: let
system = "x86_64-linux";
in {
packages.${system}.default = typix.lib.${system}.buildTypstProject {
virtualPaths = [
{
dest = "icons";
src = "${font-awesome}/svgs/regular";
}
];
};
};
}
Then, reference the files in Typst:
#image("icons/heart.svg")
Source
buildTypstProjectLocal
Returns a derivation for compiling a Typst project and copying the output to the current directory.
This is essentially a script which wraps
buildTypstProject
.
Using this derivation requires
allow-import-from-derivation
to be true
(which is the default at the time of writing).
More info: https://nixos.org/manual/nix/stable/language/import-from-derivation
Invoking the script produced by this derivation directly is currently
unsupported. Instead, use nix run
.
See this issue for more information.
Parameters
All parameters accepted by
buildTypstProject
are also accepted by
buildTypstProjectLocal
. They are repeated below for convenience.
src
Source containing all local files needed in your Typst project.
emojiFont
optional
Specify which emoji font to use. If emojiFont
is null
, no emoji font will
be included.
May be any of the following:
"twemoji"
(default)"twemoji-cbdt"
"noto"
"noto-monochrome"
"emojione"
null
— Don't include any emoji font (e.g. so you can include your own)
Note about difference between "twemoji"
and "twemoji-cbdt"
The default Twemoji font displays color emojis using the SVG font format,
which may not be supported by some systems. If emojis aren't displaying
properly, using "twemoji-cbdt"
may fix it.
fontPaths
optional
List of sources specifying paths to font files that will be made available to your Typst project. With this, you can compile Typst projects even when the fonts it uses are not available on your system.
Used for setting TYPST_FONT_PATHS
(see text#font
).
Example
{
outputs = { nixpkgs, typix }: let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
inherit (pkgs) lib;
build-script = typix.lib.${system}.buildTypstProjectLocal {
fontPaths = [
"${pkgs.roboto}/share/fonts/truetype"
];
};
in {
apps.${system}.default = {
type = "app";
program = lib.getExe build-script;
};
};
}
installPhaseCommand
optional
Command (or commands) to run during
installPhase
.
scriptName
optional
Name of the script that will be added to the Nix store. You can use this name after entering a development shell to invoke the script.
Default is typst-build
.
typstCompileCommand
optional
Base Typst command to run to compile the project. Other arguments will be appended based on the parameters you supply.
Default is typst compile
.
typstOpts
optional
Attrset specifying command-line options to pass to the typst
command.
These are in addition to any options you manually pass in
typstCompileCommand
.
Default:
{
format = "pdf";
}
Example
{
format = "png";
ppi = 300;
}
...will result in a command like:
typst compile --format png --ppi 300 <source> <output>
typstOutput
optional
Destination path for Typst output.
If omitted, it will be inferred from
typstSource
— for example,
page.typ
will become page.pdf
for PDF output.
typstSource
optional
Typst input file to compile.
Default is main.typ
.
unstable_typstPackages
optional
This is an unstable feature. Its API does not follow Semantic Versioning, and derivations relying on this feature may break at any time, even if you don't update Typst or Typix.
When this feature reaches stability, it will be renamed to typstPackages
.
(The old name will be kept as an undocumented alias, to avoid unnecessary
breakage.)
List of Typst packages to use in your Typst project, fetched from the
official Typst packages CDN at https://packages.typst.org
.
Each element of the list is an attribute set with the following keys:
name
: the package's identifier in its namespaceversion
: the package's version as a full major-minor-patch triplenamespace
(optional): the package's namespace (defaults topreview
)hash
: hash of the downloaded package tarball
hash
must be manually updated to match the hash of the package tarball downloaded
from the registry, using the "fake hash method". See Updating source hashes
for how to do this.
Sometimes, you might encounter a Typst compilation error that looks like this:
> help: error occurred while importing this module
> ┌─ @preview/cetz:0.3.4/src/canvas.typ:3:8
> │
> 3 │ #import "util.typ"
> │ ^^^^^^^^^^
> help: error occurred while importing this module
> ┌─ @preview/cetz:0.3.4/src/lib.typ:3:8
> │
> 3 │ #import "canvas.typ": canvas
> │ ^^^^^^^^^^^^
> help: error occurred while importing this module
> ┌─ main.typ:1:8
> │
> 1 │ #import "@preview/cetz:0.3.4"
> │ ^^^^^^^^^^^^^^^^^^^^^
>
For full logs, run 'nix log /nix/store/6jhjxbl7glmy4adpr5wzfgn9jvsyyipf-typst.drv'.
In this example, Nix is hiding too much output for us to diagnose the issue.
Run the command again with the -L
flag (in our case, nix run .#build -L
):
> downloading @preview/oxifmt:0.2.1
> error: failed to download package (Network Error: OpenSSL error)
> ┌─ @preview/cetz:0.3.4/src/deps.typ:1:8
> │
> 1 │ #import "@preview/oxifmt:0.2.1"
> │ ^^^^^^^^^^^^^^^^^^^^^^^
> help: error occurred while importing this module
> ┌─ @preview/cetz:0.3.4/src/util.typ:1:8
> │
> 1 │ #import "deps.typ"
> │ ^^^^^^^^^^
> help: error occurred while importing this module
> ┌─ @preview/cetz:0.3.4/src/canvas.typ:3:8
> │
> 3 │ #import "util.typ"
> │ ^^^^^^^^^^
> help: error occurred while importing this module
> ┌─ @preview/cetz:0.3.4/src/lib.typ:3:8
> │
> 3 │ #import "canvas.typ": canvas
> │ ^^^^^^^^^^^^
> help: error occurred while importing this module
> ┌─ main.typ:1:8
> │
> 1 │ #import "@preview/cetz:0.3.4"
> │ ^^^^^^^^^^^^^^^^^^^^^
We can see that cetz
is trying to import oxifmt
0.2.1, but Typst can't
download it because Nix derivations are (by design) run in an environment
which does not support networking. To fix this, add oxifmt
0.2.1 to
unstable_typstPackages
alongside your direct dependencies.
(Make sure to match the exact version shown in your error message!!)
There is currently no official support for unpublished Typst packages. However, there is a workaround.
Example
{
outputs = { nixpkgs, typix }: let
inherit (nixpkgs) lib;
system = "x86_64-linux";
build-script = typix.lib.${system}.buildTypstProjectLocal {
unstable_typstPackages = [
{
name = "cetz";
version = "0.3.4";
hash = "sha256-5w3UYRUSdi4hCvAjrp9HslzrUw7BhgDdeCiDRHGvqd4=";
}
# Transitive dependencies must be manually specified
# `oxifmt` is required by `cetz`
{
name = "oxifmt";
version = "0.2.1";
hash = "sha256-8PNPa9TGFybMZ1uuJwb5ET0WGIInmIgg8h24BmdfxlU=";
}
];
};
in {
apps.${system}.default = {
type = "app";
program = lib.getExe build-script;
};
};
}
Then you can import and use the package in Typst:
#import "@preview/cetz:0.3.4"
#cetz.canvas({
import cetz.draw: *
circle((0, 0))
line((0, 0), (2, 1))
})
virtualPaths
optional
List of sources that will be made virtually available to your Typst project. Useful for projects which rely on remote resources, such as images or data.
Each element of the list is an attribute set with the following keys:
src
: path to source file or directorydest
(optional): path where file(s) will be made available (defaults to.
)- If
src
is a directory,dest
will be a directory containing the files in that directory.- Specifying the same
dest
for multiplesrc
directories will merge them.
- Specifying the same
- If
src
is a file,dest
will be a copy of that file.
- If
Instead of an attrset, you may use a path which will be interpreted the same as
if you had specified an attrset with just src
.
Example
You can specify dependencies in your flake input, and then use them in your project with something like:
{
inputs = {
font-awesome = {
url = "github:FortAwesome/Font-Awesome";
flake = false;
};
};
outputs = { nixpkgs, typix, font-awesome }: let
system = "x86_64-linux";
inherit (nixpkgs) lib;
build-script = typix.lib.${system}.buildTypstProjectLocal {
virtualPaths = [
{
dest = "icons";
src = "${font-awesome}/svgs/regular";
}
];
};
in {
apps.${system}.default = {
type = "app";
program = lib.getExe build-script;
};
};
}
Then, reference the files in Typst:
#image("icons/heart.svg")
Source
devShell
Sets up a shell environment that activates with nix develop
or direnv
.
Parameters
Note: All parameters for mkShell
are also
supported.
emojiFont
optional
Specify which emoji font to use. If emojiFont
is null
, no emoji font will
be included.
May be any of the following:
"twemoji"
(default)"twemoji-cbdt"
"noto"
"noto-monochrome"
"emojione"
null
— Don't include any emoji font (e.g. so you can include your own)
Note about difference between "twemoji"
and "twemoji-cbdt"
The default Twemoji font displays color emojis using the SVG font format,
which may not be supported by some systems. If emojis aren't displaying
properly, using "twemoji-cbdt"
may fix it.
extraShellHook optional
Bash statements added to the shellHook
attribute.
fontPaths
optional
List of sources specifying paths to font files that will be made available to your Typst project. With this, you can compile Typst projects even when the fonts it uses are not available on your system.
Used for setting TYPST_FONT_PATHS
(see text#font
).
Example
{
outputs = { nixpkgs, typix }: let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
in {
devShells.${system}.default = typix.lib.${system}.devShell {
fontPaths = [
"${pkgs.roboto}/share/fonts/truetype"
];
};
};
}
forceVirtualPaths
optional
If there are any conflicts between virtualPaths
and files in your
project directory, they will not be overwritten unless forceVirtualPaths
is
true
.
Default is false
.
virtualPaths
optional
List of sources that will be made virtually available to your Typst project. Useful for projects which rely on remote resources, such as images or data.
Each element of the list is an attribute set with the following keys:
src
: path to source file or directorydest
(optional): path where file(s) will be made available (defaults to.
)- If
src
is a directory,dest
will be a directory containing the files in that directory.- Specifying the same
dest
for multiplesrc
directories will merge them.
- Specifying the same
- If
src
is a file,dest
will be a copy of that file.
- If
Instead of an attrset, you may use a path which will be interpreted the same as
if you had specified an attrset with just src
.
NOTE: Any paths specified here will not overwrite files in your project
directory, unless you set forceVirtualPaths
to true
.
Example
You can specify dependencies in your flake input, and then use them in your project with something like:
{
inputs = {
font-awesome = {
url = "github:FortAwesome/Font-Awesome";
flake = false;
};
};
outputs = { typix, font-awesome }: let
system = "x86_64-linux";
in {
devShells.${system}.default = typix.lib.${system}.devShell {
virtualPaths = [
{
dest = "icons";
src = "${font-awesome}/svgs/regular";
}
];
};
};
}
Then, reference the files in Typst:
#image("icons/heart.svg")
Source
mkTypstDerivation
A generic derivation constructor for running Typst commands.
Parameters
Note: All parameters for stdenv.mkDerivation
1 are also available.
buildPhaseTypstCommand
Command (or commands) to run during buildPhase
. Any
output should typically be written to $out
, e.g. typst compile <source> "$out"
.
See also: Typst CLI Usage
src
Source containing all local files needed in your Typst project.
emojiFont
optional
Specify which emoji font to use. If emojiFont
is null
, no emoji font will
be included.
May be any of the following:
"twemoji"
(default)"twemoji-cbdt"
"noto"
"noto-monochrome"
"emojione"
null
— Don't include any emoji font (e.g. so you can include your own)
Note about difference between "twemoji"
and "twemoji-cbdt"
The default Twemoji font displays color emojis using the SVG font format,
which may not be supported by some systems. If emojis aren't displaying
properly, using "twemoji-cbdt"
may fix it.
fontPaths
optional
List of sources specifying paths to font files that will be made available to your Typst project. With this, you can compile Typst projects even when the fonts it uses are not available on your system.
Used for setting TYPST_FONT_PATHS
(see text#font
).
Example
{
outputs = { nixpkgs, typix }: let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
in {
packages.${system}.default = typix.lib.${system}.mkTypstDerivation {
fontPaths = [
"${pkgs.roboto}/share/fonts/truetype"
];
};
};
}
installPhaseCommand
optional
Command (or commands) to run during
installPhase
.
unstable_typstPackages
optional
This is an unstable feature. Its API does not follow Semantic Versioning, and derivations relying on this feature may break at any time, even if you don't update Typst or Typix.
When this feature reaches stability, it will be renamed to typstPackages
.
(The old name will be kept as an undocumented alias, to avoid unnecessary
breakage.)
List of Typst packages to use in your Typst project, fetched from the
official Typst packages CDN at https://packages.typst.org
.
Each element of the list is an attribute set with the following keys:
name
: the package's identifier in its namespaceversion
: the package's version as a full major-minor-patch triplenamespace
(optional): the package's namespace (defaults topreview
)hash
: hash of the downloaded package tarball
hash
must be manually updated to match the hash of the package tarball downloaded
from the registry, using the "fake hash method". See Updating source hashes
for how to do this.
Sometimes, you might encounter a Typst compilation error that looks like this:
> help: error occurred while importing this module
> ┌─ @preview/cetz:0.3.4/src/canvas.typ:3:8
> │
> 3 │ #import "util.typ"
> │ ^^^^^^^^^^
> help: error occurred while importing this module
> ┌─ @preview/cetz:0.3.4/src/lib.typ:3:8
> │
> 3 │ #import "canvas.typ": canvas
> │ ^^^^^^^^^^^^
> help: error occurred while importing this module
> ┌─ main.typ:1:8
> │
> 1 │ #import "@preview/cetz:0.3.4"
> │ ^^^^^^^^^^^^^^^^^^^^^
>
For full logs, run 'nix log /nix/store/6jhjxbl7glmy4adpr5wzfgn9jvsyyipf-typst.drv'.
In this example, Nix is hiding too much output for us to diagnose the issue.
Run the command again with the -L
flag (in our case, nix run .#build -L
):
> downloading @preview/oxifmt:0.2.1
> error: failed to download package (Network Error: OpenSSL error)
> ┌─ @preview/cetz:0.3.4/src/deps.typ:1:8
> │
> 1 │ #import "@preview/oxifmt:0.2.1"
> │ ^^^^^^^^^^^^^^^^^^^^^^^
> help: error occurred while importing this module
> ┌─ @preview/cetz:0.3.4/src/util.typ:1:8
> │
> 1 │ #import "deps.typ"
> │ ^^^^^^^^^^
> help: error occurred while importing this module
> ┌─ @preview/cetz:0.3.4/src/canvas.typ:3:8
> │
> 3 │ #import "util.typ"
> │ ^^^^^^^^^^
> help: error occurred while importing this module
> ┌─ @preview/cetz:0.3.4/src/lib.typ:3:8
> │
> 3 │ #import "canvas.typ": canvas
> │ ^^^^^^^^^^^^
> help: error occurred while importing this module
> ┌─ main.typ:1:8
> │
> 1 │ #import "@preview/cetz:0.3.4"
> │ ^^^^^^^^^^^^^^^^^^^^^
We can see that cetz
is trying to import oxifmt
0.2.1, but Typst can't
download it because Nix derivations are (by design) run in an environment
which does not support networking. To fix this, add oxifmt
0.2.1 to
unstable_typstPackages
alongside your direct dependencies.
(Make sure to match the exact version shown in your error message!!)
There is currently no official support for unpublished Typst packages. However, there is a workaround.
Example
{
outputs = { typix }: let
system = "x86_64-linux";
in {
packages.${system}.default = typix.lib.${system}.mkTypstDerivation {
unstable_typstPackages = [
{
name = "cetz";
version = "0.3.4";
hash = "sha256-5w3UYRUSdi4hCvAjrp9HslzrUw7BhgDdeCiDRHGvqd4=";
}
# Transitive dependencies must be manually specified
# `oxifmt` is required by `cetz`
{
name = "oxifmt";
version = "0.2.1";
hash = "sha256-8PNPa9TGFybMZ1uuJwb5ET0WGIInmIgg8h24BmdfxlU=";
}
];
};
};
}
Then you can import and use the package in Typst:
#import "@preview/cetz:0.3.4"
#cetz.canvas({
import cetz.draw: *
circle((0, 0))
line((0, 0), (2, 1))
})
virtualPaths
optional
List of sources that will be made virtually available to your Typst project. Useful for projects which rely on remote resources, such as images or data.
Each element of the list is an attribute set with the following keys:
src
: path to source file or directorydest
(optional): path where file(s) will be made available (defaults to.
)- If
src
is a directory,dest
will be a directory containing the files in that directory.- Specifying the same
dest
for multiplesrc
directories will merge them.
- Specifying the same
- If
src
is a file,dest
will be a copy of that file.
- If
Instead of an attrset, you may use a path which will be interpreted the same as
if you had specified an attrset with just src
.
Example
You can specify dependencies in your flake input, and then use them in your project with something like:
{
inputs = {
font-awesome = {
url = "github:FortAwesome/Font-Awesome";
flake = false;
};
};
outputs = { typix, font-awesome }: let
system = "x86_64-linux";
in {
packages.${system}.default = typix.lib.${system}.mkTypstDerivation {
virtualPaths = [
{
dest = "icons";
src = "${font-awesome}/svgs/regular";
}
];
};
};
}
Then, reference the files in Typst:
#image("icons/heart.svg")
Source
Footnotes
stdenv
(not for the faint of heart)
watchTypstProject
Returns a derivation for a script that watches an input file and recompiles on changes.
Parameters
Note: All parameters for
writeShellApplication
are also supported
(besides text
).
emojiFont
optional
Specify which emoji font to use. If emojiFont
is null
, no emoji font will
be included.
May be any of the following:
"twemoji"
(default)"twemoji-cbdt"
"noto"
"noto-monochrome"
"emojione"
null
— Don't include any emoji font (e.g. so you can include your own)
Note about difference between "twemoji"
and "twemoji-cbdt"
The default Twemoji font displays color emojis using the SVG font format,
which may not be supported by some systems. If emojis aren't displaying
properly, using "twemoji-cbdt"
may fix it.
fontPaths
optional
List of sources specifying paths to font files that will be made available to your Typst project. With this, you can compile Typst projects even when the fonts it uses are not available on your system.
Used for setting TYPST_FONT_PATHS
(see text#font
).
Example
{
outputs = { nixpkgs, typix }: let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
inherit (pkgs) lib;
watch-script = typix.lib.${system}.watchTypstProject {
fontPaths = [
"${pkgs.roboto}/share/fonts/truetype"
];
};
in {
apps.${system}.default = {
type = "app";
program = lib.getExe watch-script;
};
};
}
forceVirtualPaths
optional
If there are any conflicts between virtualPaths
and files in your
project directory, they will not be overwritten unless forceVirtualPaths
is
true
.
Default is false
.
scriptName
optional
Name of the script that will be added to the Nix store. You can use this name after entering a development shell to invoke the script.
Default is typst-watch
.
typstOpts
optional
Attrset specifying command-line options to pass to the typst
command.
These are in addition to any options you manually pass in
typstWatchCommand
.
Default:
{
format = "pdf";
}
Example
{
format = "png";
ppi = 300;
}
...will result in a command like:
typst watch --format png --ppi 300 <source> <output>
typstOutput
optional
Destination path for Typst output.
If omitted, it will be inferred from
typstSource
— for example,
page.typ
will become page.pdf
for PDF output.
typstSource
optional
Typst input file to compile.
Default is main.typ
.
typstWatchCommand
optional
Base Typst command to run to watch the project. Other arguments will be appended based on the other parameters you supply.
Default is typst watch
.
virtualPaths
optional
List of sources that will be made virtually available to your Typst project. Useful for projects which rely on remote resources, such as images or data.
Each element of the list is an attribute set with the following keys:
src
: path to source file or directorydest
(optional): path where file(s) will be made available (defaults to.
)- If
src
is a directory,dest
will be a directory containing the files in that directory.- Specifying the same
dest
for multiplesrc
directories will merge them.
- Specifying the same
- If
src
is a file,dest
will be a copy of that file.
- If
Instead of an attrset, you may use a path which will be interpreted the same as
if you had specified an attrset with just src
.
NOTE: Any paths specified here will not overwrite files in your project
directory, unless you set forceVirtualPaths
to true
.
Example
You can specify dependencies in your flake input, and then use them in your project with something like:
{
inputs = {
font-awesome = {
url = "github:FortAwesome/Font-Awesome";
flake = false;
};
};
outputs = { nixpkgs, typix, font-awesome }: let
system = "x86_64-linux";
inherit (nixpkgs) lib;
watch-script = typix.lib.${system}.watchTypstProject {
virtualPaths = [
{
dest = "icons";
src = "${font-awesome}/svgs/regular";
}
];
};
in {
apps.${system}.default = {
type = "app";
program = lib.getExe watch-script;
};
};
}
Then, reference the files in Typst:
#image("icons/heart.svg")
Source
Utilities
cleanTypstSource
Filters a source tree to only contain *.typ
files and special files such as
typst.toml
.
Example
{
outputs = { nixpkgs, typix }: let
system = "x86_64-linux";
typixLib = typix.lib.${system};
in {
packages.${system}.default = typixLib.mkTypstDerivation {
src = typixLib.cleanTypstSource ./.;
};
};
}