What is flyp?

flyp is the official package manager for Fly. It handles everything outside the compiler itself: creating projects, declaring and fetching dependencies, locking versions for reproducible builds, and invoking the fly compiler with the right flags and include paths.

flyp ships alongside the fly compiler as a separate binary in the same installation archive. If you have Fly installed, you have flyp.

$ flyp --version
flyp 0.1.0

Project structure

A Fly project managed by flyp has this layout:

my-project/
├── fly.toml        # manifest — project metadata and dependencies
├── fly.lock        # lockfile — exact resolved versions (commit to VCS)
└── src/
    └── main.fly    # entry point (auto-detected)

fly.toml is written by hand. fly.lock is generated by flyp and must never be edited manually.


fly.toml reference

fly.toml is the project manifest. It uses TOML syntax.

[package]

Required section that describes the project itself.

[package]
name        = "my-app"
version     = "0.1.0"
description = "A brief description of what this project does"
license     = "Apache-2.0"
fly-version = "0.1.0"
homepage    = "https://example.com"           # optional
repository  = "https://github.com/you/my-app" # optional
authors     = ["Your Name <[email protected]>"]  # optional
FieldRequiredDescription
nameyesPackage name. Must match [a-z0-9_-]+
versionyesSemantic version in MAJOR.MINOR.PATCH format
descriptionyesShort description
licenseyesSPDX license identifier
fly-versionyesMinimum Fly compiler version required
homepagenoProject website
repositorynoSource repository URL
authorsnoList of author strings

[[bin]]

Declares an executable target. If omitted, flyp auto-detects src/main.fly.

[[bin]]
name = "my-app"
path = "src/main.fly"

[[bin]]
name = "cli-tool"
path = "src/cli.fly"

[[lib]]

Declares a library target. If omitted, flyp auto-detects src/lib.fly.

[[lib]]
name = "my-lib"
path = "src/lib.fly"
type = "static"    # "static" (default) or "shared"

[[test]]

Declares a test suite target.

[[test]]
name = "unit"
path = "test/unit.fly"

[[test]]
name = "integration"
path = "test/integration.fly"

[dependencies]

Runtime dependencies fetched from Git repositories.

[dependencies]
mylib    = { git = "https://github.com/example/mylib.git", tag = "v1.2.0" }
core     = { git = "https://github.com/example/core.git",  branch = "main" }
patched  = { git = "https://github.com/example/utils.git", rev = "a3f1c29d" }

Each dependency must specify exactly one of:

KeyDescription
tagA Git tag — recommended for released versions
branchA Git branch — always fetches the latest commit on that branch
revA full 40-character commit hash — the most reproducible option

[dev-dependencies]

Dependencies used only for tests and development tools. Not fetched in release builds and not propagated to packages that depend on yours.

[dev-dependencies]
test-utils = { git = "https://github.com/example/test-utils.git", tag = "v0.3.0" }

[profile.debug] and [profile.release]

Build profiles control how the Fly compiler optimises and instruments the output.

[profile.debug]
opt-level  = 0      # 0–3
debug-info = true   # emit DWARF debug information
assertions = true   # enable runtime assertions

[profile.release]
opt-level  = 3
debug-info = false
lto        = false  # link-time optimisation
strip      = false  # strip symbols from output binary
assertions = false

Creating a project

$ flyp init

Creates fly.toml and src/main.fly in the current directory, using the directory name as the package name.

$ flyp init --name my-app

Creates a new subdirectory my-app/ with the same layout.

$ flyp init --name my-app --version 0.2.0

Specifies an initial version other than the default 0.1.0.

After flyp init:

my-app/
├── fly.toml
└── src/
    └── main.fly

Managing dependencies

Adding a dependency

$ flyp add mylib --git https://github.com/example/mylib.git --tag v1.2.0

flyp adds the entry to fly.toml, then immediately resolves and fetches all dependencies, writing a fresh fly.lock.

$ flyp add core --git https://github.com/example/core.git --branch main
$ flyp add patched --git https://github.com/example/utils.git --rev a3f1c29d8e2b...

Add a development-only dependency with --dev:

$ flyp add test-utils --git https://github.com/example/test-utils.git --tag v0.3.0 --dev

Removing a dependency

$ flyp remove mylib

Removes the entry from fly.toml (both [dependencies] and [dev-dependencies]) and regenerates fly.lock.

Updating dependencies

Update a single package to the latest commit on its configured branch or tag:

$ flyp update mylib

Update all dependencies at once:

$ flyp update

flyp update clears the affected cache entries and re-runs resolution, so it will pick up new commits on tracked branches or newer tags if you change fly.toml manually.


The lockfile

fly.lock records the exact commit hash, checksum, and dependency tree for every package in the build. A minimal lockfile looks like this:

# fly.lock — generated automatically by flyp.
# Do not edit manually.
# Commit alongside fly.toml for reproducible builds.

version  = 1
flyp     = "0.1.0"
checksum = "sha256:e3b0c44298fc1c149afbf4c8996fb924..."

[[package]]
name         = "mylib"
version      = "1.2.0"
source       = "git+https://github.com/example/mylib.git"
rev          = "a3f1c29d8e2b4f1a7c3d5e6b8f9a0b1c2d3e4f5a"
tag          = "v1.2.0"
checksum     = "sha256:9f86d081884c7d659a2feaa0c55ad015..."
dependencies = []

Always commit fly.lock to version control. It guarantees that every developer and every CI run compiles the exact same code.

The lockfile is automatically regenerated whenever fly.toml changes. flyp detects staleness by storing a SHA-256 checksum of fly.toml inside the lockfile itself.


Version resolution (MVS)

flyp uses Minimum Version Selection (MVS), the same algorithm used by Go Modules. The rules are simple:

  1. Collect all version constraints from the root manifest and all transitive dependencies via breadth-first traversal.
  2. For each package, select the highest version among all constraints — this is the minimum version that satisfies everyone.
  3. If two constraints refer to the same package name but different Git URLs, resolution fails with error E001.

Example

root         → mylib v1.0.0
root         → framework v2.0.0
framework    → mylib v1.5.0   ← higher constraint

MVS selects mylib v1.5.0. No SAT solver, no backtracking — deterministic and fast.

Why the highest version?

Because it is the minimum version that satisfies the most demanding constraint. Lower versions would break framework, and picking an arbitrary higher version would be non-deterministic.


Building

Compile all targets in debug mode:

$ flyp build

Compile with the release profile (optimised, no debug info):

$ flyp build --release

Build a specific target by name:

$ flyp build --target my-app

Output goes to target/debug/ or target/release/ in the project root.

If fly.lock is stale when you run flyp build, flyp automatically re-locks before building.


Running

Build and immediately run the default binary:

$ flyp run

Pass arguments to the binary after --:

$ flyp run -- --port 8080 --verbose

Choose which binary to run in a multi-binary project:

$ flyp run --bin cli-tool
$ flyp run --release --bin server

Testing

Build and run all test suites:

$ flyp test

Run only one suite by name:

$ flyp test unit

Run tests with release optimisations:

$ flyp test --release

Each test target is compiled and executed as a standalone binary. flyp reports pass/fail per suite.


Understanding the dependency graph

flyp why <package> explains why a package is included and which constraint caused it to be selected.

$ flyp why mylib

Example output:

mylib v1.5.0 is included because:

  root v0.1.0  (requires mylib tag v1.0.0)
  framework v2.0.0  (requires mylib tag v1.5.0)

resolved: mylib 1.5.0 satisfies all 2 constraint(s)

This makes it easy to understand diamond dependencies and trace unexpected version selections.


Resolving the lockfile manually

Run resolution explicitly without building:

$ flyp lock

Useful in CI pipelines to separate the "resolve" step from the "build" step, or to pre-populate the cache.


Cache management

flyp stores fetched packages in a local cache so they are not re-downloaded on every build.

Path (default)Description
~/.flyp/cache/<host>/<owner>/<repo>/<rev>/Cached source tree

Override the cache location with the environment variable $FLYP_HOME:

export FLYP_HOME=/opt/flyp

Inspect the cache

$ flyp cache stats
Cache: /home/user/.flyp/cache
  142 files, 3891 KB

Clear the cache

$ flyp cache clean
Cache cleared: /home/user/.flyp/cache

Error reference

flyp reports structured errors with a code, context, and a hint.

E001 — Dependency conflict

Two packages require the same dependency from different Git URLs. flyp cannot reconcile this automatically.

error[E001]: dependency conflict — cannot resolve

conflict chain:
  root → mylib  (git=https://github.com/example/mylib.git tag=v1.0.0)
  fork-lib → mylib  (git=https://github.com/fork/mylib.git tag=v1.0.0)

hint: run `flyp why mylib` to see all constraints

Resolution: ensure all packages in your dependency tree reference the same Git URL for a given package name, or fork one of the conflicting packages under a different name.

E002 — Package not found

The specified tag, branch, or commit hash does not exist in the remote repository.

error[E002]: package not found

package: mylib
source:  https://github.com/example/mylib.git
tag "v3.0.0" not found in repository
available: v1.0.0, v1.2.0, v2.0.0

hint: did you mean tag = "v2.0.0"?

Resolution: check the tag or branch name in fly.toml. Use flyp update after correcting it.


CLI reference

CommandDescription
flyp init [--name NAME] [--version VER]Create a new Fly project
flyp build [--release] [--target NAME]Build all or one target
flyp run [--release] [--bin NAME] [-- ARGS]Build and run a binary
flyp test [--release] [SUITE]Build and run test suites
flyp add NAME --git URL (--tag|--branch|--rev) [--dev]Add a dependency
flyp remove NAMERemove a dependency
flyp update [NAME]Update one or all dependencies
flyp lockResolve and write fly.lock
flyp why NAMEExplain why a package is included
flyp cache statsShow cache size
flyp cache cleanRemove all cached packages
flyp versionPrint flyp version
flyp search QUERYSearch the package registry (coming soon)
flyp publishPublish to the package registry (coming soon)