Skip to content

Package Manager

tulpar pkg is the built-in package manager for Tulpar. It manages project dependencies via a small TOML manifest (tulpar.toml) and writes a deterministic lockfile (tulpar.lock) on every install so your tulpar_modules/ tree is reproducible across machines.

The official package registry lives at pkg.tulparlang.dev — point [registry] url there in your manifest to install community packages.

Terminal window
# Inside an empty project directory
tulpar pkg init my-api
# Add a local-path dependency (development)
tulpar pkg add greeter@path:../greeter
# Add a single-file URL dependency
tulpar pkg add lodash@url:http://my-cdn/lodash.tpr
# Add a semver-style registry dependency (requires [registry] url in tulpar.toml)
tulpar pkg add wings@1.2.3
# Vendor everything into ./tulpar_modules
tulpar pkg install

After tulpar pkg install, the consumer can import "greeter" and the runtime resolves it from tulpar_modules/greeter/greeter.tpr.

tulpar.toml is a deliberately tiny TOML subset — string values only, top-level keys plus [registry] and [dependencies] tables.

name = "my-api"
version = "0.1.0"
description = "Tulpar HTTP API example"
author = "Hamza"
license = "MIT"
[registry]
url = "https://pkg.tulparlang.dev"
[dependencies]
wings = "1.2.3" # registry
greeter = "path:../greeter" # local sibling dir
lodash = "url:http://cdn/lodash.tpr" # single-file URL
FormMeaning
path:./local/dirRecursively copy *.tpr from a local directory.
url:http://example.com/x.tprPlain HTTP fetch of a single .tpr file.
1.2.3 (or ^0.2.0, *)Registry fetch. Resolves to <registry>/<name>/<spec>.tpr

A registry version spec requires [registry] url = "..." in the manifest. https:// URLs require Tulpar to be built with OpenSSL (pacman -S mingw-w64-x86_64-openssl on MSYS2).

After every successful pkg install, Tulpar writes tulpar.lock next to your manifest:

# tulpar.lock — auto-generated by `tulpar pkg install`.
# DO NOT EDIT. Commit alongside tulpar.toml so re-installs are reproducible.
[resolved]
wings = "https://pkg.tulparlang.dev/wings/1.2.3.tpr"
greeter = "path:../greeter"
lodash = "url:http://cdn/lodash.tpr"

The lockfile records the fully resolved URL or path used for each dependency so a re-install on another machine fetches the exact same bytes — even if the registry’s latest pointer moves.

When the AOT compiler sees import "name", it tries (in order):

  1. The literal path ./name.
  2. The literal path with .tpr appended (./name.tpr).
  3. ./tulpar_modules/<name>/<name>.tpr — the vendored entry-point convention.
  4. ./tulpar_modules/<name>.tpr — single-file vendor.
  5. The embedded standard library (wings, router, http_client, orm, test, …).

That ordering means a local name.tpr shadows a vendored package, and the embedded stdlib only kicks in if nothing else resolves.

CommandEffect
tulpar pkg init [name]Create a starter tulpar.toml (refuses to overwrite).
tulpar pkg listPrint package metadata + dependencies.
tulpar pkg add <name>[@<ver-spec>]Add or update a manifest dependency line.
tulpar pkg remove <name>Drop a manifest dependency line.
tulpar pkg installVendor every dep into tulpar_modules/ + write tulpar.lock.
  • Multi-file packages via tar/zip extract from registry URLs.
  • Real semver range resolution (^1.2, >=1,<2).
  • Package signing + cryptographic checksum in the lockfile.