Typix Logo
Typix

FlakeHub version

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 changes
  • nix 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 changes
  • nix 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:

For a more complete description of how to specify flake inputs, see the Nix Reference Manual section on flakerefs.

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:

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
└── ...
1

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 to typst commands via the TYPST_FONT_PATHS environment variable.
  • Files in virtualPaths will be recursively symlinked to the current directory (only overwriting existing files when forceVirtualPaths is true).
  • For convenience, the typst-watch script is added, which will run watchTypstProject.

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:

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:

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.

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:

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 namespace
  • version: the package's version as a full major-minor-patch triple
  • namespace (optional): the package's namespace (defaults to preview)
  • 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 directory
  • dest (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 multiple src directories will merge them.
    • If src is a file, dest will be a copy of that file.

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:

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 namespace
  • version: the package's version as a full major-minor-patch triple
  • namespace (optional): the package's namespace (defaults to preview)
  • 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 directory
  • dest (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 multiple src directories will merge them.
    • If src is a file, dest will be a copy of that file.

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:

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 directory
  • dest (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 multiple src directories will merge them.
    • If src is a file, dest will be a copy of that file.

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.mkDerivation1 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:

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 namespace
  • version: the package's version as a full major-minor-patch triple
  • namespace (optional): the package's namespace (defaults to preview)
  • 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 directory
  • dest (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 multiple src directories will merge them.
    • If src is a file, dest will be a copy of that file.

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

1

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:

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 directory
  • dest (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 multiple src directories will merge them.
    • If src is a file, dest will be a copy of that file.

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 ./.;
    };
  };
}