Packaging
This page explains how to turn your Mojo project into a distributable conda package using rattler-build.
You can distribute your conda package on any conda-compatible package index, such as prefix.dev, anaconda.org, or an S3 bucket. For the most visibility, we recommend sharing your package in the modular-community channel on prefix.dev, as described below.
How it works
rattler-build is a tool that turns your source code into a conda package.
You give it a recipe—a YAML file named recipe.yaml—and it does the
rest: fetches your source, compiles it in an isolated environment, runs your
tests, and writes out a .conda file ready to upload to a package index.
The recipe is a declarative description of your package that specifies:
- The source code location (a git commit or tarball URL)
- The build process (a
mojo packagecommand) - Package dependencies
- Test commands to verify the build
The complete packaging process is:
- Create a
recipe.yamlthat specifies your package details. - Run
rattler-buildto create a.condapackage. - Share the package in a public package index.
Then you and other users can install your package with pixi or other conda
package managers by adding the appropriate conda channel to your project
manifest file (pixi.toml).
Install rattler-build
We recommend using Pixi to install rattler-build:
-
If you don't have it, install
pixiwith this command:curl -fsSL https://pixi.sh/install.sh | shThen restart your terminal for the changes to take effect.
-
Now install
rattler-buildglobally:pixi global install rattler-build -
Verify the installation:
rattler-build --version
Write your recipe file
The recipe is the heart of the packaging process and is defined in a YAML file
named recipe.yaml.
By convention, store your recipe in your project root at
conda.recipe/recipe.yaml. rattler-build looks there by default, and it's
the location expected by the GitHub Action
(rattler-build-action).
For example:
my-mojo-lib/
├── src/
│ └── my_mojo_lib/
│ ├── __init__.mojo
│ └── utils.mojo
├── test.mojo
├── conda.recipe/
│ └── recipe.yaml
├── LICENSE
└── README.mdThe minimal recipe file
This section covers the most important recipe fields for Mojo packages. For details about all available recipe fields, see the rattler-build recipe reference.
You can copy this template to begin building your recipe.yaml file:
context:
version: "0.1.0"
package:
name: my-mojo-lib
version: ${{ version }}
source:
- git: https://github.com/yourname/my-mojo-lib.git
rev: a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2
build:
number: 0
script:
- mojo package src/my_mojo_lib -o ${{ PREFIX }}/lib/mojo/my_mojo_lib.mojopkg
requirements:
build:
- mojo-compiler =25.5.0
host:
- mojo-compiler =25.5.0
run:
- ${{ pin_compatible('mojo-compiler') }}
tests:
- script:
- if: unix
then:
- mojo run test.mojo
files:
recipe:
- test.mojo
about:
homepage: https://github.com/yourname/my-mojo-lib
repository: https://github.com/yourname/my-mojo-lib
license: MIT
license_file: LICENSE
summary: A short one-line description of what your library does.
extra:
maintainers:
- yournameRecipe tips
Here are a few things that are particularly important for Mojo packages.
Use a full commit SHA as the source revision
The source.rev field should be a full 40-character git commit SHA rather than
a branch name or tag. This makes the build reproducible—anyone who builds from
the same recipe gets the exact same source code.
Set the build number
Start build.number at 0. If you need to rebuild the same version of your
library (such as to pick up a new Mojo compiler release), increment
build.number rather than changing the version. Reset it to 0 when you bump
the version.
Specify the install location
In the above recipe, look at the mojo package command in the build.script
section. It's important that this command outputs the .mojopkg file into
$PREFIX/lib/mojo/, because this path is what makes the package
auto-discoverable by the Mojo compiler.
When rattler-build runs your build script, it sets a $PREFIX environment
variable pointing to the root of an isolated installation directory. Any files
your script places under $PREFIX become part of the conda package—a file
written to $PREFIX/lib/mojo/foo.mojopkg during the build is extracted into
your actual environment when you run pixi add foo. Think of $PREFIX as a
stand-in for wherever your environment lives on your machine.
Pin the Mojo compiler version
Mojo packages compile against a specific compiler version and might not be
compatible with other versions. The required mojo-compiler version must be
specified in the requirements.build section of your recipe, which must conform
to the
conda package match syntax.
The pin_compatible('mojo-compiler') function
in requirements.run generates a version constraint based on whichever version
is resolved at build time, preventing your package from silently running
against an incompatible runtime.
Build the package
With your recipe file in hand, you can build the package using rattler-build
from your project root:
rattler-build build \
--recipe conda.recipe/recipe.yaml \
-c conda-forge \
-c https://conda.modular.com/max \
-c https://repo.prefix.dev/modular-communityThe -c flags specify which conda channels to search for dependencies (in
priority order). You need:
conda-forgefor general toolinghttps://conda.modular.com/maxformojo-compilerandmaxhttps://repo.prefix.dev/modular-communityif you depend on other community Mojo packages
When you run rattler-build build, it:
- Creates an isolated build environment
- Fetches your source code
- Runs your build script to compile the
.mojopkgfile - Bundles the result into a
.condaarchive - Runs your test commands to verify the package works
The output file appears in an output/ directory, for example:
output/
└── linux-64/
└── my-mojo-lib-0.3.0-h1a2b3c4_0.condaThe hash in the filename (h1a2b3c4) is derived from the build configuration
and is managed automatically by rattler-build.
Debug a failed build
If the build fails, open a debug shell to investigate interactively:
rattler-build debug shellThis gives you a shell with all environment variables set ($PREFIX,
$SRC_DIR, etc.) and the build environment activated, so you can run your
build commands to find the problem.
For more details, see the rattler-build debugging guide.
Publish to a package index
Once you have a built .conda file, you can upload it to any compatible host,
such as prefix.dev, anaconda.org,
or an AWS S3 bucket. For the most visibility, add your package to the
modular-community channel
(hosted on prefix.dev), as described below.
Publish to the modular-community channel
To publish your package on the modular-community
channel, open a pull
request to the modular-community GitHub
repo to add your package's
recipe.yaml file. The repo automatically builds and hosts all the packages
based on the recipes in the repo.
Your recipe.yaml is the same file described above. Just add it to a new
directory that matches your package name:
modular-community/
└── recipes/
└── my-mojo-lib/
└── recipe.yamlOnce published to the channel, you can install your package with pixi by
adding the https://repo.prefix.dev/modular-community channel to your
project manifest:
[workspace]
channels = [
"https://conda.modular.com/max-nightly",
"https://repo.prefix.dev/modular-community",
"conda-forge",
]For more details, see the modular-community README.
Update your package
When you release a new version of your library:
- Update
context.versionin your recipe. - Update
source.revto the new commit SHA (or update the tarball URL and SHA256). - Reset
build.numberto0. - Open a new PR to modular-community (if you've already published it there).
If you're republishing the same version (for example, to support a new Mojo
compiler release), increment build.number instead of changing the version.
Useful links
Was this page helpful?
Thank you! We'll create more content like this.
Thank you for helping us improve!