Join the forge!

History of conda-forge, adding your recipes, and how to get involved


Travis Hathaway DoEPy Python Exchange September 2026

Who am I?

  • Professional software engineer πŸ’»
  • Amateur musician 🎸🎢🎀
  • Work at Anaconda on conda packaging πŸ“¦
Anaconda logo Conda logo
Travis Hathaway

Travis Hathaway

(a.k.a. pretty chill guy)

Overview

  • History of conda-forge
  • Submitting your own recipes (i.e. packages)
  • How to get involved as a volunteer
01

History of conda-forge

From compiling everything by hand to 30,000+ packages

It's 2012...

Call Me Maybe
Gangam Style

You're still
writing Python 2.7
by hand

You're still
compiling everything
by hand 🀯

Context

Python packaging before conda

  • The community was moving from easy_install/eggs to pip, but there was no easy way to ship pre-compiled packages
  • Wheels weren't formalized until 2013 (PEP 427); on Windows, Christoph Gohlke's builds were often your only option
  • Linux users had to compile from source — manylinux wheels didn't exist until PEP 513 in 2016
Binary compatibility

Why building from source was the default

numpy 1.7.0 on PyPI (Feb 2013): source tarball + six 32-bit Windows .exe installers. Nothing for macOS or Linux.

  • Jun 2014 — first macOS wheel (1.8.1)
  • Mar 2016 — first 64-bit Windows wheel (1.10.4)
  • Apr 2016 — first Linux wheels, manylinux1 (1.11.0)

Until then, pip install numpy on Linux meant a C compiler, gfortran, and a BLAS/LAPACK you had to find yourself.

GCC logo Fortran logo
Origins

Enter conda (2012–2013)

  • 2012: Continuum Analytics announces Anaconda 0.8 at SciPy; in September, conda 1.0 ships as a cross-platform, language-agnostic package manager for pre-compiled artifacts
  • conda packages could ship compiled shared libraries and Python itself, not just Python code
  • By June 2013: conda gets a SAT solver, conda build ships, Miniconda and Binstar.org (hosting for user-built conda packages) launch
…at the first PyData meetup at Google HQ, where several of us asked Guido what we can do to fix Python packaging for the NumPy stack. Guido's answer was to ‘solve the problem ourselves.’ We at Continuum took him at his word… and created the conda package manager and conda environments.

Travis Oliphant, Why I promote conda (2013)

2014

From shared recipes to fragmented channels

  • ContinuumIO/conda-recipes became the central place to contribute conda recipes — but quality varied, most recipes only worked on 1–2 platforms, and there was no CI
  • Groups adopted Binstar/Anaconda.org for their own needs: Omnia (Molecular Dynamics, Mar 2014), the Met Office's SciTools (Jun 2014), IOOS (Jul 2014)
  • Phil Elson (SciTools) built CI + tooling (conda-build-all); Filipe Fernandes (IOOS) borrowed it — lots of cross-pollination, but duplicated recipes and unpredictable compatibility when mixing channels
Milestone April 11, 2015

conda-forge is registered as a GitHub organization and an Anaconda.org channel

2016-17

Divergence with a common base

  • conda-forge steadily grows its own feedstocks while Anaconda's main channel is born
  • Pressure is mounting to move faster by adopting new build toolchains
  • conda-forge becomes the public base that Anaconda's main channel is built on top of
  • Allows conda-forge to move independently and freely

Key Differences

conda-forge

  • Supported and run by volunteers
  • Free to use (free as in freedom πŸ₯²)
     
  • Anyone can submit a recipe via a formal process

Anaconda's main

  • Commercial product operated by Anaconda
  • Free-ish* (free for certain enterprises and groups <200 people)
  • Adding recipes for outsiders is more opaque, not impossible though!
Growth

Feedstocks over time

Where we are now

conda-forge today

30,000+

packages

8,000+

maintainers

10+

years old (since 2015)

27

core team members

27

enhancement proposals (CFEPs)

Where we are now

A global community

79

countries & territories

63%

of maintainers are outside the US

4,900+

maintainers list a location

02

How to submit your own recipe

Your package's front door: conda-forge/staged-recipes

Overview

staged-recipes: the front door

flowchart TB
  A["Fork and branch off main"] --> C["Add recipes/#lt;package#gt;/"]
  C --> D["Open a PR"]
  D --> E["CI builds on<br/>Linux, macOS, Windows"]
  E --> F["Review"]
  F --> G["Merge"]
  class G done
  • staged-recipes is an entry point for recipes destined to become their own feedstock
  • After merging, each recipe gets its own feedstock repository
Naming

Why "forge" and "feedstock"?

  • Forge: A place where raw metal is worked into useful things
  • Feedstock: the raw material fed into an industrial process. In metallurgy: ore, fuel and scrap loaded into the furnace
  • In conda-forge, a feedstock repo holds the raw inputs (source + recipe) that CI feeds through the forge to produce finished packages
Molten metal pouring into a cast
Photo: yasin hemmati on Unsplash
Getting started

Generating a recipe

Use a generator

  • Python packages on PyPI:
    grayskull pypi --use-v1-format <package>
  • R packages on CRAN:
    grayskull cran --use-v1-format <package>

Start from the example

Anything else — copy recipes/example-v1/recipe.yaml and edit by hand, following the section order and removing the explainer comments.

Python Example

context:
  name: zensus2pgsql
  version: 0.2.1
  python_min: "3.10"

package:
  name: ${{ name|lower }}
  version: ${{ version }}

source:
  url: https://pypi.org/packages/source/${{ name[0] }}/${{ name }}/zensus2pgsql-${{ version }}.tar.gz
  sha256: 00517129cf7747e7580f57c680e143de5e5accca928407cd79bc88c114502ec5

build:
  number: 0
  noarch: python
  script: ${{ PYTHON }} -m pip install . -vv --no-deps --no-build-isolation
  python:
    entry_points:
      - zensus2pgsql = zensus2pgsql.cli:app
      - zpg = zensus2pgsql.cli:app

requirements:
  host:
    - python ==${{ python_min }}
    - hatchling >=1.27.0
    - pip
  run:
    - python >=${{ python_min }}
    - aiocsv >=1.4.0
    - aiofiles >=25.1.0
    - asyncpg >=0.30.0
    - httpx >=0.28.1
    - platformdirs >=4.5.0
    - rich >=14.2.0
    - typer >=0.15.1
    - types-aiofiles >=25.1.0.20251011

tests:
  - python:
      imports:
        - zensus2pgsql
        - zensus2pgsql.commands.create
        - zensus2pgsql.commands.cache
        - zensus2pgsql.commands.drop
        - zensus2pgsql.commands.list
        - zensus2pgsql.cache
        - zensus2pgsql.constants
        - zensus2pgsql.errors
        - zensus2pgsql.logging
        - zensus2pgsql.retry
      pip_check: true
  - requirements:
      run:
        - python ==${{ python_min }}
    script:
      - zensus2pgsql --help
      - zpg --help

about:
  summary: A Python CLI program that collects Zensus GIS data from Germany and imports it into PostgreSQL
  license: GPL-3.0-only
  license_file: COPYING
  homepage: https://travishathaway.github.io/zensus2pgsql

extra:
  recipe-maintainers:
    - travishathaway
Dependencies

requirements: build / host / run

Section What goes here Typical examples
build Tools needed only while building, not on the host Compilers, cmake, make, pkg-config
host Present alongside the package at build time Shared C/C++ libraries, python/r-base, pip, setuptools
run Needed only when the package runs Most Python/R runtime libraries
C/C++ Example

context:
  version: 2.3.1

recipe:
  name: osm2pgsql
  version: ${{ version }}

source:
  - url: https://github.com/osm2pgsql-dev/osm2pgsql/archive/refs/tags/${{ version }}.tar.gz
    sha256: e90461bd78787fd5cf82f73ac4bc0cfccbc4f498f35dce59eb4d168a380d6ac0

build:
  number: 1

package:
  name: osm2pgsql
  version: ${{ version }}

build:
  number: 1
  script:
    - if: unix
      then: build.sh
      else: build.bat

requirements:
  build:
    - ${{ compiler('cxx') }}
    - ${{ stdlib('c') }}
    - cmake
    - ninja
    - pkg-config
  host:
    - expat
    - proj
    - bzip2
    - zlib
    - postgresql
    - lua
    - protozero
    - libosmium
    - cli11
    - fmt <12
    - nlohmann_json
    - libboost-devel
  run:
    - lua
    - osm2pgsql-replication

tests:
  - files:
      recipe:
        - test.sh
        - liechtenstein-2013-08-03.osm.pbf
    requirements:
      run:
        - postgresql
        - if: unix
          then: postgis
    script:
      - osm2pgsql --version
      - osm2pgsql --help
      - if: unix
        then: bash test.sh

about:
  homepage: https://osm2pgsql.org
  license: GPL-2.0-only
  license_file:
    - COPYING
  summary: Import OpenStreetMap data into a PostgreSQL/PostGIS database
  description: osm2pgsql is a tool for loading OpenStreetMap data into a PostgreSQL / PostGIS database suitable for applications like rendering into a map, geocoding with Nominatim, or general analysis.
  documentation: https://osm2pgsql.org
  repository: https://github.com/osm2pgsql-dev/osm2pgsql

extra:
  recipe-maintainers:
    - travishathaway
Quality bar

Every recipe needs tests

  • At minimum: existence tests — verify the package installed the files you expect (package_contents in v1)
  • Python packages: a python: test with imports: + automatic pip_check: true
  • R packages: an r: test with libraries:
  • Command-line tools: run <tool> --help to prove it's on PATH and executable
  • The goal is testing that the conda package built and installed correctly — not re-running the upstream project's full test suite
Checklist

Before you open the PR

  • License uses the correct SPDX identifier and case (Apache-2.0, not APACHE 2.0)
  • A license_file is included, unless the upstream tarball already ships one
  • Build from a tarball (url:), never git_url: — tarballs are checksummable and smaller
  • Remove the example's explainer comments from your copy of the recipe
  • Leave the recipes/example-v1/ folder itself untouched
What happens next

Review → merge → feedstock

Getting reviewed

Mention the appropriate language team (e.g. @conda-forge/help-python) in a PR comment; first-time contributors can ask a bot to ping the team for them.

After merge

CI creates <package>-feedstock automatically, triggers the first build, uploads to anaconda.org/conda-forge, and invites you to the conda-forge GitHub org with commit rights on your new feedstock.

What's next

Congrats, you're a maintainer πŸ₯³ πŸŽ‰

  • Merge routine maintenance PRs opened by conda-forge's bots
  • Bump the version + checksum whenever upstream releases
  • Keep requirements accurate as the package's dependencies change
  • Answer questions on the feedstock's issue tracker
A crowd watching fireworks burst in the night sky
GIF: Ranch9613 / Wikimedia Commons (CC0)
03

Get involved: review staged recipes

The community that keeps the front door open

Why it matters

staged-recipes always needs reviewers

  • It's one of the highest-traffic repos in conda-forge — every new package waits here for a review
  • Review times vary from days to weeks to months 😱 depending on how many volunteers are active on a given language team
  • Straight from the maintainers: “We are always looking for more staged-recipe reviewers”
Community

Review teams by language

Language GitHub team Open Pull Requests
Python @conda-forge/help-python 167
Rust @conda-forge/help-rust 38
Python/C hybrid @conda-forge/help-python-c 37
C/C++ @conda-forge/help-c-cpp 33
R @conda-forge/help-r 19
NodeJS @conda-forge/help-nodejs 11
Java @conda-forge/help-java 7
The gap

Why C/C++, R, Rust and Java need you

  • These ecosystems tend to have more compiler-heavy, platform-specific build logic
  • Fewer reviewers are comfortable evaluating those recipes, so PRs in these languages wait longer
  • Python is the most popular language in the world, so it's easier to find reviewers
Volunteering

How to join a review team

  • Interested volunteers can reach out to a member of
    @conda-forge/core
  • On top of this, the best way is to dig in and start commenting and reviewing on pull requests yourself
  • Hangout with us on Zulip and ping me! (Travis Hathaway)
In practice

What reviewing looks like day to day

  • Can take as little as 5 minutes a day (ditch your morning crossword for a pull request review! πŸ˜›)
  • Find a build that's failing, examine the logs and find ways to get it working
  • Making sure submitted recipes check all the boxes (including licenses, no or limited use of vendoring, passes linter checks)
  • Scientifically proven to stimulate brain growth and foster new neural pathway connections*
*results of scientific studies proving this still outstanding.