Guide: Submitting a Package to Modular Community
A comprehensive guide for submitting Mojo packages to the modular-community channel, based on real experience submitting DataBooth/mojo-toml.
Official documentation: https://www.modular.com/community/package-submission
Overview
The modular-community channel allows you to distribute your Mojo packages so they can be installed via pixi add by anyone in the community. Packages are built using rattler-build and distributed through the MAX Builds platform.
Prerequisites
1. Your Package Repository Setup
Before submitting, ensure your package has:
- β
Git tags for releases (e.g.,
v0.9.1) - β LICENSE file in repository root
- β README.md with clear documentation
- β Tests that can be run to verify the package works
- β
Clear project structure with source code in a consistent location (e.g.,
src/packagename/)
2. Security & Quality Requirements
- β
Enable CodeQL scanning in your repository
- Go to Settings β Security β Code scanning β Set up β Choose βDefaultβ
- Add CodeQL badge to README:
[](https://github.com/USER/REPO/actions/workflows/codeql.yml)
- β
Package image for builds.modular.com display (512Γ512 PNG, named
image.png) - β Tests pass on all target platforms (macOS, Linux)
3. Local Development Tools
Install required tools:
# GitHub CLI (for PR management)
brew install gh
gh auth login
# Fork and clone the modular-community repository
gh repo fork modular/modular-community --clone
cd modular-communityStep-by-Step Submission Process
Step 1: Create Your Recipe Branch
cd /path/to/modular-community
# Fetch latest changes
git fetch origin
git checkout main
git pull origin main
# Create a new branch for your package
git checkout -b add-YOURPACKAGE-v0.1.0Naming convention: add-YOURPACKAGE-vX.Y.Z (e.g., add-mojo-toml-v0.9.1)
Step 2: Create Recipe Directory Structure
mkdir -p recipes/YOURPACKAGE
cd recipes/YOURPACKAGEYour recipe directory should contain: - recipe.yaml - Package recipe (required) - test_package.mojo - Test file (required) - image.png - Logo/icon for builds.modular.com (512Γ512 PNG)
Step 3: Create recipe.yaml
Use this template and customize for your package:
package:
name: mojo-toml
version: 0.9.1
source:
git: https://github.com/DataBooth/mojo-toml.git
tag: v0.9.1 # Git tag in your repo
build:
number: 0 # Increment for same version, reset to 0 for new version
script:
# Copy source files to PREFIX location
- mkdir -p $PREFIX/lib/mojo/toml
- cp -r src/toml/* $PREFIX/lib/mojo/toml/
requirements:
build:
- mojo-compiler =1.0.0b1
host:
- mojo-compiler =1.0.0b1
run:
- ${{ pin_compatible('mojo-compiler') }}
tests:
- script:
# Verify files were installed correctly
- test -f $PREFIX/lib/mojo/toml/__init__.mojo
- test -f $PREFIX/lib/mojo/toml/parser.mojo
about:
homepage: https://github.com/DataBooth/mojo-toml
license: Apache-2.0 # Use SPDX identifier
license_file: LICENSE
summary: Native TOML 1.0 parser and writer for Mojo - Complete + Partial 1.1 π₯
description: |
mojo-toml is a native TOML 1.0 parser and writer for Mojo, enabling
fast and efficient parsing and writing of TOML configuration files with zero
Python dependencies.
Features:
- Complete TOML 1.0 specification support
- TOML writer with full round-trip fidelity
- 168 comprehensive tests (100% passing)
- Zero Python dependencies
documentation: https://github.com/DataBooth/mojo-toml/blob/main/README.md
repository: https://github.com/DataBooth/mojo-toml
extra:
recipe-maintainers:
- mjboothaus # Your GitHub usernameKey Fields Explained
Context Variables (optional but recommended):
context:
version: "0.9.1"
package:
version: ${{ version }} # Reference context variableSource Section: - Use tag: for stable releases (recommended) - Use rev: for specific commit SHA if needed - The tag/rev must exist in your GitHub repository
Build Number: - Start at 0 for first submission of a version - Increment for recipe fixes without version change - Reset to 0 when version changes
Build Script: - Use $PREFIX environment variable for install location - Standard path: $PREFIX/lib/mojo/PACKAGENAME/ - For .mojopkg files: $PREFIX/lib/mojo/PACKAGENAME.mojopkg
Requirements: - build: Tools needed during build - host: Runtime dependencies for building - run: Runtime dependencies for users - Use ${{ pin_compatible('mojo-compiler') }} to lock Mojo compiler compatibility
Test Commands: - Verify installed files exist - Run basic smoke tests - Keep tests quick (< 30 seconds)
License: - Must use SPDX identifier (see https://spdx.org/licenses/) - Common: MIT, Apache-2.0, BSD-3-Clause, GPL-3.0-only
Step 4: Create test_package.mojo
Create a test file that verifies your package works:
"""Test that mojo-toml package is installed and functional."""
from toml import parse
fn main() raises:
# Test basic parsing
var toml_str = """
title = "Test"
count = 42
enabled = true
"""
var data = parse(toml_str)
# Verify parsed correctly
var title = data["title"].as_string()
var count = data["count"].as_int()
var enabled = data["enabled"].as_bool()
# Basic assertions
if title != "Test":
raise Error("Title parsing failed")
if count != 42:
raise Error("Integer parsing failed")
if not enabled:
raise Error("Boolean parsing failed")
print("β All tests passed")
Step 5: Create Package Image
Create a 512Γ512 PNG logo named image.png:
# If you have an existing logo
cp /path/to/your/logo.png recipes/YOURPACKAGE/image.png
# Or create a simple one with Python/PIL
python3 << 'EOF'
from PIL import Image, ImageDraw, ImageFont
size = (512, 512)
img = Image.new('RGB', size, color='#1E1E1E')
draw = ImageDraw.Draw(img)
# Draw your logo design here
# ... (customize as needed)
img.save('recipes/YOURPACKAGE/image.png')
print("β Created image.png")
EOFThe image will be displayed on builds.modular.com when your package is featured.
Step 6: Commit and Push
# Add all recipe files
git add recipes/YOURPACKAGE/
# Commit with descriptive message
git commit -m "Add YOURPACKAGE v0.1.0 - Brief description
- Package description
- Key features
- Any relevant notes"
# Push to your fork
git push origin add-YOURPACKAGE-v0.1.0Step 7: Create Pull Request
Using GitHub CLI:
# Create PR body file
cat > /tmp/pr_body.md << 'EOF'
Adds YOURPACKAGE v0.1.0 - Brief description of your package.
**Package features:**
- Feature 1
- Feature 2
- Feature 3
**Testing:**
- β
Tests pass locally
- β
CodeQL scanning enabled
- β
Package image included
Repository: https://github.com/YOU/YOURPACKAGE
EOF
# Create the PR
gh pr create \
--repo modular/modular-community \
--base main \
--head YOURUSERNAME:add-YOURPACKAGE-v0.1.0 \
--title "Add YOURPACKAGE v0.1.0 - Brief description" \
--body-file /tmp/pr_body.mdUpdating Your Package
For New Version (e.g., 0.9.0 β 0.9.1)
cd modular-community
git checkout main
git pull origin main
# Create new branch for updated version
git checkout -b add-YOURPACKAGE-v0.9.1
# Update recipe.yaml
# - Change package.version to 0.9.1
# - Change source.tag to v0.9.1 (or appropriate tag)
# - Reset build.number to 0
git add recipes/YOURPACKAGE/recipe.yaml
git commit -m "Update YOURPACKAGE to v0.9.1"
git push origin add-YOURPACKAGE-v0.9.1
# Create new PR
gh pr create --repo modular/modular-community ...For Recipe Fix (same version)
# Make changes to recipe.yaml
# Increment build.number (e.g., 0 β 1)
git add recipes/YOURPACKAGE/recipe.yaml
git commit -m "Fix YOURPACKAGE recipe: description of fix"
git push origin add-YOURPACKAGE-v0.9.1Common Issues & Solutions
Issue: PR not showing package image
Problem: Old PR branch may be cached by GitHub.
Solution: Create fresh PR with new branch name
git checkout -b add-YOURPACKAGE-vX.Y.Z-v2 # Add suffix
git push origin add-YOURPACKAGE-vX.Y.Z-v2
# Close old PR and create new oneIssue: Tests failing in CI
Problem: Package not found or test errors.
Solution: 1. Check test_package.mojo imports match installed paths 2. Verify build script copies files correctly 3. Test locally with pixi if possible
Issue: Build number confusion
Problem: When to increment build number vs version?
Solution: - New version (0.9.0 β 0.9.1): Reset build.number to 0 - Recipe fix (same 0.9.1): Increment build.number (0 β 1 β 2) - New PR for same version: Usually keep build.number at 0
Issue: License identifier unclear
Problem: βMIT Licenseβ vs βMITβ?
Solution: Always use SPDX identifier from https://spdx.org/licenses/ - β
MIT - β
Apache-2.0 - β
BSD-3-Clause - β MIT License - β Apache 2.0
PR Review Process
After submitting your PR:
Automated checks will run (CI tests, lint checks)
Reviewer will check:
- Recipe format is correct
- Tests pass on all platforms
- Package image is present
- License is properly specified
- Security requirements met (CodeQL)
Address feedback if needed:
# Make changes locally git add recipes/YOURPACKAGE/ git commit -m "Address review feedback: specific change" git push origin add-YOURPACKAGE-vX.Y.Z # PR updates automaticallyMerge: Once approved, maintainers will merge your PR
After Merge
Your package will be available via:
pixi add YOURPACKAGEUsers can then import and use it in their Mojo projects!
Best Practices
Version Management
- Use semantic versioning (X.Y.Z)
- Tag releases in your repository before submitting
- Keep recipe version in sync with git tag
Documentation
- Include clear README.md in your repository
- Add usage examples
- Document any platform-specific requirements
Testing
- Test on both macOS and Linux if possible
- Include tests that verify core functionality
- Keep tests fast (< 30 seconds total)
Maintenance
- Respond promptly to PR feedback
- Monitor your packageβs issues on modular-community
- Update package when dependencies change
Checklist
Before submitting, verify:
Resources
- Official guide: https://www.modular.com/community/package-submission
- rattler-build docs: https://prefix-dev.github.io/rattler-build/
- SPDX licenses: https://spdx.org/licenses/
- Modular forum: https://forum.modular.com/
- Discord: Join #package-submission channel
Example Packages
Reference these for examples: - mojo-toml: https://github.com/DataBooth/mojo-toml - hue: https://github.com/thatstoasty/hue - Browse recipes: https://github.com/modular/modular-community/tree/main/recipes
Getting Help
- Forum: https://forum.modular.com/ (package-submitter topic)
- Discord: #package-submission channel
- Email: caroline@modular.com (@caroline_frasca)
This guide is based on the experience of submitting mojo-toml v0.9.1 to modular-community in January 2026.
Lessons Learned & Best Practices
β Recipe Schema Requirements (Critical!)
Issue: Recipe parser is strict about field names and structure.
Required schema (not optional):
# β WRONG - Will fail CI
test:
commands:
- test -f $PREFIX/lib/mojo/package/__init__.mojo
about:
doc_url: https://github.com/user/package/blob/main/README.md
dev_url: https://github.com/user/package
# β
CORRECT - Will pass CI
tests:
- script:
- test -f $PREFIX/lib/mojo/package/__init__.mojo
about:
documentation: https://github.com/user/package/blob/main/README.md
repository: https://github.com/user/packageKey differences: - Use tests: (plural) not test: - Use script: block, not commands: - Tests must be a list (note the - before script:) - Use documentation: not doc_url - Use repository: not dev_url
Prevention: Use local validation (see next section)
β Local Validation Setup
Problem: Schema errors arenβt caught until CI runs, wasting time.
Solution: Validate locally before submission.
Setup in your package repo:
Add validation script:
scripts/validate-recipe.shAdd GitHub Actions:
.github/workflows/validate-recipe.ymlAdd to pre-commit:
- repo: local hooks: - id: validate-recipe name: Validate recipe.yaml schema entry: ./scripts/validate-recipe.sh language: system files: ^packaging/recipe\\.yaml$ pass_filenames: false
Usage:
./scripts/validate-recipe.sh packaging/recipe.yamlSee RECIPE_VALIDATION.md for complete setup guide.
β Mojo Version Management
Best practice: Use context variables for version management.
Recommended pattern:
context:
version: 0.9.1
mojo_version: "=1.0.0b1" # Current migration target
package:
name: mojo-package
version: ${{ version }}
requirements:
build:
- mojo-compiler ${{ mojo_version }}
host:
- mojo-compiler ${{ mojo_version }}
run:
- ${{ pin_compatible('mojo-compiler') }}Benefits: - Single place to update Mojo version - pin_compatible() allows compatible patch/minor updates within your selected compiler series - Clear which version was tested
When to update: When new stable Mojo releases (check Mojo changelog)
β Pre-commit Hygiene
Issue: Trailing whitespace, incorrect line endings cause CI failures.
Solution: Install and run pre-commit in your package repos.
Setup:
cd your-package-repo
pixi run bash -c "pre-commit install"
pixi run bash -c "pre-commit run --all-files"Common fixes pre-commit catches: - Trailing whitespace - Missing final newlines - YAML/TOML syntax errors - Mixed line endings
Automate: Pre-commit runs on every git commit once installed.
β Git Tag Management
Critical: Recipe tag: field must match an actual git tag in your repo.
Common mistake:
package:
version: 0.9.1
source:
tag: v0.9.0 # β Version mismatch!Correct approach:
# 1. Make sure tag exists
git tag v0.9.1
git push --tags
# 2. Then reference it in recipe
source:
tag: v0.9.1 # β
Matches package versionWorkflow: 1. Commit all changes 2. Create and push git tag: git tag -a v0.9.1 -m "v0.9.1 - Description" && git push --tags 3. Update recipe.yaml with matching version/tag 4. Submit PR to modular-community
β Platform Considerations
Your packages are likely cross-platform:
If your package: - β Ships pure Mojo source code - β Has no platform-specific dependencies - β Doesnβt compile binaries during install
Consider adding:
build:
number: 0
noarch: generic # Single build for all platformsBenefits: - 3x faster CI (one build vs. three) - ~66% less storage - Faster user installs
When NOT to use noarch: - Building .mojopkg files (platform-specific binaries) - Using platform-specific tools in build script - Running compiled tests
See PLATFORM_BUILDS.md for details.
β PR Workflow Tips
After submitting PR:
- CI needs approval - First-time contributors need maintainer approval to run workflows
- Be patient - CI runs take 5-15 minutes across 3 platforms
- Watch for feedback - Reviewers may request changes (schema, tests, documentation)
- Update efficiently - Fix issues, commit, push to same branch (PR auto-updates)
Common review requests: - Add package image - Enable CodeQL scanning - Fix recipe schema (tests:, documentation:, repository:) - Update license to Apache-2.0 (if applicable) - Add missing test files
Iteration workflow:
# 1. Fix locally first
./scripts/validate-recipe.sh packaging/recipe.yaml
# 2. Commit changes
git add recipes/your-package/
git commit -m "Address review feedback: fix schema"
# 3. Push (PR updates automatically)
git push origin add-your-package-v0.1.0Checklist Before Submission
Use this checklist before creating your PR:
Your Package Repo: - [ ] Git tag exists and pushed (e.g., v0.9.1) - [ ] CodeQL enabled with badge in README - [ ] Pre-commit hooks installed and passing - [ ] Tests pass locally - [ ] LICENSE file exists - [ ] Package image created (512Γ512 PNG)
Recipe Files: - [ ] packaging/recipe.yaml validates locally (./scripts/validate-recipe.sh packaging/recipe.yaml) - [ ] Uses tests: (plural) with script: block - [ ] Uses documentation: and repository: (not doc_url/dev_url) - [ ] tag: matches package version: - [ ] test_package.mojo exists and tests core functionality - [ ] image.png exists (512Γ512 PNG)
PR Quality: - [ ] Branch name: add-PACKAGE-vX.Y.Z - [ ] PR title clear: βAdd package-name vX.Y.Zβ - [ ] PR description includes features, use case, compliance checklist - [ ] All files committed and pushed
Resources
Official: - Modular Community Package Submission - rattler-build Documentation - Mojo Changelog
Package-Specific: - RECIPE_VALIDATION.md - Local validation setup - PLATFORM_BUILDS.md - Cross-platform considerations - ROADMAP.md - Future improvements (noarch, etc.)
Community: - modular-community GitHub - Mojo Discord
Document version: 2.0
Last updated: 2026-01-29
Maintainer: @mjboothaus