typst-pack
Bundle a Typst project and its fonts and packages into one file that can compile on another machine.
A pack (.typk) contains an entrypoint, the project's source and data files,
and the exact package and font requirements found during a representative
compile. Packages and fonts can be embedded for offline, portable compilation
or recorded as external requirements for the receiving application to supply.
Use the CLI to create, inspect, compile, and extract packs. Use the Rust library to build the same workflows in editors, web services, object-storage systems, and other applications.
This is unrelated to Typst's bundle output (typst-bundle). A pack is portable
input for later compilation, not a collection of rendered output files.
Features
- Put a whole Typst project in one
.typkfile, including images and data. - Vendor imported Typst Universe packages so compilation works offline.
- Embed selected fonts so output does not depend on fonts installed elsewhere.
- Compile to PDF, PNG, SVG, or experimental HTML without reading ambient project files.
- Replace a contained project file for one compile without changing the pack.
- Inspect or extract a pack before using it.
- Build packs from the filesystem, entirely in memory, or with caller-supplied OpenDAL storage.
- Keep filesystem access and network download support as separate build choices.
CLI
Install the command-line tool:
cargo install typst-pack-cli
# Pack a named source file, vendoring all observed packages:
typst-pack create path/to/project/main.typ
# Pack a specific entrypoint, embedding the fonts the document uses:
typst-pack create letter.typ --embed-fonts
# See what a pack contains:
typst-pack inspect project.typk
# Compile a pack without network access:
typst-pack compile project.typk output.pdf
# Replace a contained placeholder for one compilation:
typst-pack compile invoice.typk customer.pdf --override assets/logo.png customer-logo.png
# PNG or SVG output, page selection, reproducible builds:
typst-pack compile project.typk "page-{0p}.png" --ppi 300 --pages 1-3
typst-pack compile project.typk reproducible.pdf --creation-timestamp 1700000000
# Guarantee no network access (fails instead of downloading packages):
typst-pack compile project.typk --offline
# Experimental HTML export:
typst-pack compile project.typk out.html
typst-pack create project/main.typ --target html --features html
# Unpack a pack back into an editable project directory:
typst-pack extract project.typk -o project/
For PNG and SVG output, {p} is the one-based source page number, {0p} and
{n} are zero-padded aliases, and {t} is the source-document page count.
Multi-page output needs a page placeholder. All output paths are checked for
duplicates before anything is written.
See CLI examples for additional create, compile, extraction, and Pack Override commands.
Project files
create includes every eligible regular file beneath the project root, not
only files reached by the representative compile. A root .typkignore uses
Gitignore-style ordered rules. It is included in the pack; nested
.typkignore files are ordinary files. Symlinks, unsupported entries, and any
path containing a .typk component are rejected.
The representative compile selects package and font requirements. Its target,
inputs, date, features, and control flow do not change which project files are
included. Pack a valid placeholder when a document needs per-recipient data,
then replace it with --override PACK_PATH FILE at compile time.
Packages and fonts
Observed packages are embedded by default. --no-vendor-packages records each
exact package and complete tree identity instead; compilation then requires the
application's configured package sources to provide a matching tree. --offline
prevents downloads during both creation and compilation.
Fonts are external by default. --embed-fonts stores selected font containers
except those shipped by Typst; --include-typst-embedded-fonts stores those as
well. Mind font licenses when redistributing embedded files.
Output formats
PDF and HTML produce one artifact. PNG and SVG produce one artifact for each
selected source page. HTML is experimental in Typst. The complete intentional
differences from typst compile are listed in the
CLI parity inventory.
Library
The core in-memory packing, creation, and compilation APIs need no crate features. Add filesystem support when the library should read local projects, package directories, and system fonts:
[]
= { = "0.6", = ["embedded-fonts", "fs"] }
The fs feature links no network client. Add egress only when filesystem
assembly should download missing Typst Universe packages.
The library contract describes identity, dependency fulfillment, environment independence, write policies, retry material, and partial effects. The OpenDAL guide documents asynchronous storage integration.
Common workflows
Each entry links to a compile-checked example on docs.rs, so the code shown there is verified against the release you are reading about.
| Task | Start here |
|---|---|
| Pack a project directory from disk | FilesystemPackAssembler |
| Pack in-memory bytes with no filesystem | Pack::builder |
| Supply packages yourself and resume creation | create |
| Swap a contained file for one compile | PackOverrideSet |
| Read and write packs through object storage | OpenDAL guide |
The shortest complete example — build a pack in memory and encode it:
use Pack;
use encode;
let pack = builder
.file
.expect
.build
.expect;
let archive = encode.expect;
assert!;
Pack::builder does not discover dependencies: the pack contains exactly the
files added to it. Use create when the library should run dependency
discovery over values the caller already holds, and a Pack Assembler when it
should also read those values from a source.
Pack creation is stateless and resumable. If the representative compile reaches
a package that is not in the supplied catalog, creation reports that exact
specification instead of failing; add its tree and call create again. The
package-reading feature provides official registry URL construction and
bounded .tar.gz expansion without choosing an HTTP client, and OpenDAL
provides read_package and insert_read_package for the same lifecycle over
configured operators.
A Pack Override can replace only a project path already contained in the pack. It cannot add a path or change package or font requirements.
Feature flags
fs: Read projects, local packages, caches, and system fonts from the filesystem; unavailable on wasm targets.egress: Download missing packages during filesystem assembly; impliesfsandpackage-readingand links HTTP/TLS dependencies.package-reading: Construct registry URLs, read bounded package archives, and expand them without choosing a transport.opendal: Use caller-polled OpenDAL reads and writes with caller-supplied operators and runtime support.embedded-fonts: Make Typst's bundled fonts available to assembly and external fulfillment.diagnostics: Retain source context for first-party diagnostic presentation adapters.parallel: Export independent page artifacts in parallel.
All features are opt-in. Featureless creation and compilation remain available
on wasm32-unknown-unknown.
Migrating
Migrating to 0.6
Version 0.6 standardizes storage vocabulary on read and write. The
rename was generated from git diff fb610cb..HEAD; there are no compatibility
aliases.
| Before 0.6 | 0.6 |
|---|---|
Feature package-acquisition |
package-reading |
Module typst_pack::opendal::publication |
typst_pack::opendal::write |
gather_filesystem_project |
read_filesystem_project |
gather_filesystem_font_catalog |
read_filesystem_fonts |
gather_filesystem_package |
read_filesystem_package |
FilesystemPackageAuthority::acquire |
FilesystemPackageAuthority::read |
acquire_package_archive |
read_package_archive |
opendal::pack_assembly::acquire_project |
read_project |
opendal::pack_assembly::acquire_fonts |
read_fonts |
opendal::pack_assembly::acquire_package |
read_package |
opendal::pack_archive::acquire_pack_archive |
read_pack_archive |
opendal::publication::publish_pack_archive |
opendal::write::write_pack_archive |
publish_package_cache_archive |
write_package_cache_archive |
publish_pack_extraction_plan |
write_pack_extraction_plan |
publish_compilation_artifacts |
write_compilation_artifacts |
publish_pack_extraction_plan_to_filesystem |
write_pack_extraction_plan_to_filesystem |
publish_pack_extraction_plan_to_filesystem_with_fault_probe |
write_pack_extraction_plan_to_filesystem_with_fault_probe |
publish_compilation_artifacts_to_filesystem_paths |
write_compilation_artifacts_to_filesystem_paths |
resolve_filesystem_publication_paths |
resolve_filesystem_write_paths |
CompilationArtifactPathPublicationError::publication_error |
CompilationArtifactPathWriteError::write_error |
insert_acquired_package |
insert_read_package |
pack_archive::acquire / acquire_file |
pack_archive::read / read_file |
pack_archive::publish / publish_file |
pack_archive::write / write_file |
Type families follow the same mechanical rules:
| Before 0.6 | 0.6 |
|---|---|
*Acquisition* |
*Read* |
*Publication* |
*Write* |
*GatherError |
*ReadError |
Acquired* |
Read* |
PublicationPolicy |
WritePolicy |
PublicationKeyOutcome |
WriteKeyOutcome |
PackArchiveAcquisitionError |
PackArchiveReadError |
ProjectAcquisitionRequest |
ProjectReadRequest |
PackageAcquisitionLimits |
PackageReadLimits |
AcquiredPackageInsertionError |
ReadPackageInsertionError |
FilesystemPackageAcquisitionError |
FilesystemPackageAuthorityReadError |
PackExtractionPublicationProgress |
PackExtractionWriteProgress |
CompilationArtifactPublicationReceipt |
CompilationArtifactWriteReceipt |
FilePublicationPolicy |
FileWritePolicy |
OpenDAL operation errors are no longer generic over an OperatorResolver error
type. Resolver failures are retained as boxed sources. Match the operation's
typed cause, then downcast the source to the concrete error supplied by your
resolver:
use ProjectReadErrorCause;
if let ResolveOperator = error.cause
Compilation and encoding now have convenient reference limits. Use
compile(request) and pack_archive::encode(pack) for the built-in profiles;
use compile_with_limits, encode_with_limits, write_pack_with_limits, or
save_pack_with_limits to narrow them. Limits remain required at trust
boundaries, including archive decoding, package expansion, stream/file reads,
and filesystem or OpenDAL read requests. Invalid custom limit configurations
are programmer errors and panic during construction.
Pack Extraction and Compilation Output Artifact writes now share the crate-root
*WriteEntry, *WriteProgress, and *WriteReceipt types across filesystem and
OpenDAL adapters. Write errors retain progress where relevant and expose
CommitCertainty; successful receipts do not make an atomicity claim.
The request-origin and inventory wrappers were removed:
CompilationRequestInventory, TypstInputsInventory, PackOverridesInventory,
PackOverrideInventoryEntry, EffectiveRequestValue, RequestValueOrigin, and
CompilationOutputOrigins. Configure values directly on
PackCompilationRequest. Fulfillment provenance remains available through
PackageTreeFulfillment, FontContainerFulfillment, and the fulfillment report;
CompilationAccessTrace also remains available on a result.
CanonicalIdentity and CanonicalIdentityRole now implement Display,
rendering as role:digest. Equality is unchanged and still covers role, schema,
and algorithm, so compare whole identity values rather than the rendered string.
Dependency-fulfillment failures report what is missing. Every
CompilationFulfillmentIssue message names the package or font container
involved instead of dumping a Debug projection, and
InvalidCompilationFulfillmentSet no longer summarizes a single issue as a
count. Present these failures through issues(): the aggregate Display is a
summary, not the detail.
typst-pack inspect gained a required fonts section listing the external Font
Requirements a recipient must supply, and its embedded fonts lines now use the
shorter role:digest identity form. typst-pack compile reports each
unfulfilled dependency as a hint with the recovery to try.
The egress feature no longer links rustls-pemfile. Custom --cert PEM
parsing moved to rustls-pki-types, which absorbed it; behavior is unchanged,
including that a file with no PEM section adds no trust anchor.
Migrating to 0.5
Version 0.5 added the optional OpenDAL adapter. Existing builds that do not
enable opendal are unaffected. Applications that enable it must select their
own backend, transport, runtime, credentials, and retry behavior. See
Migrating to 0.5 for dependency,
composition, target, identity, and cache guidance.
Migrating to 0.4
Version 0.4 made clean breaks without compatibility aliases:
- Remove Resource Slot and Resource Provider APIs; pack placeholders and replace them with Pack Overrides.
- Rename Dagger arguments:
source->project,entrypoint->input,inputs->sysInputs,noPackages->noVendorPackages,sourceDateEpoch->creationTimestamp, andCreationTarget->TypstTarget. - Change creation from a directory plus
--entrypoint/--outputtocreate <INPUT> [OUTPUT]. - Replace
compile_pack(request)withcompile(request); the arbitrary-Worldoverload and publicPackWorldbuilder are removed. - Read accepted compilation results from
CompilationReport::outcome()orresult();compile_report,PackCompileError,CompilationAttempt, andCompilationExecutionControlsare removed. - Replace
CreationTargetandCompilationTargetwithTypstTarget, and configure time with oneDocumentTime. - Replace
PackerwithFilesystemPackAssemblerConfig,FilesystemPackAssembler, andFilesystemPackAssemblyRequest. - Read representative-compile warnings from
PackAssemblyReport::warnings;PackReportis removed. - Inspect domain values through
Packaccessors rather than Pack Manifest records. - Handle shared Pack consistency failures through
PackInvariantError::issues(). - Replace
OutputFormatplusCompileOptionsrequest construction with aCompilationOutputSpecificationvariant. - Replace
extractwithplan_pack_extractionfollowed bywrite_pack_extraction_plan_to_filesystemand an explicitFilesystemMergePolicy.
The unstable Pack format remains version 1, but discovery and Resource Slot fields were removed in place. Old fields and aliases are not accepted.
Pack format
A pack is a Zip archive, conventionally named *.typk, with this layout:
typst-pack.toml manifest
project/<path> project files, root-relative
packages/<ns>/<name>/<version>/<path> embedded package files
fonts/<file> embedded font files
Example manifest:
= 1
[]
= "main.typ"
[[]]
= "@preview/cetz:0.3.4"
= "0123456789abcdef0123456789abcdef"
= "complete-package-tree"
= "typst-pack-complete-package-tree-v1"
= "typst-hash128-0.15"
= 12
= 34567
[[]]
= "fonts/ibm-plex-sans.ttf"
= ["IBM Plex Sans"]
[]
= "Quarterly report"
= ["Jane Doe"]
The encoder writes Deflate-compressed version-1 archives. Readers accept safe interoperable ZIP encodings and member orderings, ignore safe unknown entries, and reject unknown format versions, unsafe paths, unsupported entry kinds, and inconsistent manifests. Decoding and re-encoding preserves Pack semantics, not exact ZIP bytes, compression settings, timestamps, unknown entries, or member order. Format version 1 is explicitly unstable.
Development
Minimum verification:
cargo fmt --all -- --checkcargo clippy --workspace --all-targets --all-features -- -D warningscargo test --workspace --all-featuresdagger check
Maintainers changing the embedded compiler must follow the embedded Typst upgrade procedure.
License
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.