.. Copyright Spack Project Developers. See COPYRIGHT file for details. SPDX-License-Identifier: (Apache-2.0 OR MIT) .. meta:: :description lang=en: Learn how to set up and manage package repositories in Spack, enabling you to maintain custom packages and override built-in ones. .. _repositories: Package Repositories (repos.yaml) ================================= Spack comes with thousands of built-in package recipes. As of Spack v1.0, these are hosted in a separate Git repository at `spack/spack-packages `_. A **package repository** is a directory that Spack searches when it needs to find a package by name. You may need to maintain packages for restricted, proprietary, or experimental software separately from the built-in repository. Spack allows you to configure local and remote repositories using either the ``repos.yaml`` configuration file or the ``spack repo`` command. This document describes how to set up and manage these package repositories. Structure of an Individual Package Repository --------------------------------------------- An individual Spack package repository is a directory structured as follows: .. code-block:: text /path/to/repos/ # the top-level dir is added to the Python search path spack_repo/ # every package repository is part of the spack_repo Python module myrepo/ # directory for the 'myrepo' repository (matches namespace) repo.yaml # configuration file for this package repository packages/ # directory containing package directories hdf5/ # directory for the hdf5 package package.py # the package recipe file mpich/ # directory for the mpich package package.py # the package recipe file mpich-1.9-bugfix.patch # example patch file trilinos/ package.py ... * ``repo.yaml``. This file contains metadata for this specific repository, for example: .. code-block:: yaml repo: namespace: myrepo api: v2.0 It defines primarily: * ``namespace``. A unique identifier for this repository (e.g., ``myrepo``, ``projectx``). See the :ref:`Namespaces ` section for more details. * ``api``. The version of the Spack Package API this repository adheres to (e.g., ``v2.0``). Spack itself defines what range of API versions it supports, and will error if it encounters a repository with an unsupported API version. * ``packages/``. This directory contains subdirectories for each package in the repository. Each package directory contains a ``package.py`` file and any patches or other files needed to build the package. Package repositories allow you to: 1. Maintain your own packages separately from Spack's built-in set. 2. Share your packages (e.g., by hosting them on a shared file system or in a Git repository) without committing them to the main ``spack/spack-packages`` repository. 3. Override built-in Spack packages with your own implementations. Packages in a separate repository can also *depend on* built-in Spack packages, allowing you to leverage existing recipes without re-implementing them. Package Names ^^^^^^^^^^^^^ Package names are defined by the directory names under ``packages/``. In the example above, the package names are ``hdf5``, ``mpich``, and ``trilinos``. Package names can only contain lowercase characters ``a-z``, digits ``0-9`` and hyphens ``-``. .. note:: Package names are **derived** from the directory names under ``packages/``. Package directories are required to be valid Python module names, which means they cannot contain hyphens or start with a digit. This means that a package named ``my-package`` would be stored in a directory named ``my_package/``, and a package named ``7zip`` would be stored in a directory named ``_7zip/`` with an underscore prefix to make it a valid Python module name. The mapping between package names and directory names is one-to-one. Use ``spack list`` to see how Spack resolves the package names from the directory names. Configuring Repositories with ``repos.yaml`` -------------------------------------------- Spack uses ``repos.yaml`` files found in its :ref:`configuration scopes ` (e.g., ``~/.spack/``, ``etc/spack/``) to discover and prioritize package repositories. Note that this ``repos.yaml`` (plural) configuration file is distinct from the ``repo.yaml`` (singular) file within each individual package repository. Spack supports two main types of repository configurations: Local Repositories (Path-based) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ You can point Spack to a repository on your local filesystem: .. code-block:: yaml :caption: ``~/.spack/repos.yaml`` :name: code-example-local-repo repos: my_local_packages: /path/to/my_repository_root Here, ``/path/to/my_repository_root`` should be the directory containing that repository's ``repo.yaml`` and ``packages/`` subdirectory. Git-based Repositories ^^^^^^^^^^^^^^^^^^^^^^ Spack can clone and use repositories directly from Git URLs: .. code-block:: yaml repos: my_remote_repo: https://github.com/myorg/spack-custom-pkgs.git Automatic Cloning """"""""""""""""" When Spack first encounters a Git-based repository configuration, it automatically clones it. By default, these repositories are cloned into a subdirectory within ``~/.spack/package_repos/``, named with a hash of the repository URL. To change directories to the package repository, you can use ``spack cd --repo [name]``. To find where a repository is cloned, you can use ``spack location --repo [name]`` or ``spack repo list``. The ``name`` argument is optional; if omitted, Spack will use the first package repository in configuration order. Customizing Clone Location """""""""""""""""""""""""" The default clone location (``~/.spack/package_repos/``) might not be convenient for package maintainers who want to make changes to packages. You can specify a custom local directory for Spack to clone a Git repository into, or to use if the repository is already cloned there. This is done using the ``destination`` key in ``repos.yaml`` or via the ``spack repo set --destination`` command (see :ref:`cmd-spack-repo-set-destination`). For example, to use ``~/custom_packages_clone`` for ``my_remote_repo``: .. code-block:: yaml :caption: ``~/.spack/repos.yaml`` :name: code-example-location repos: my_remote_repo: git: https://github.com/myorg/spack-custom-pkgs.git destination: ~/custom_packages_clone If the ``git`` URL is defined in a lower-precedence configuration (like Spack's defaults for ``builtin``), you only need to specify the ``destination`` in your user-level ``repos.yaml``. Spack can make the configuration changes for you using ``spack repo set --destination ~/spack-packages builtin``, or you can directly edit your ``repos.yaml`` file: .. code-block:: yaml :caption: ``~/.spack/repos.yaml`` :name: code-example-builtin repos: builtin: destination: ~/spack-packages Updating and pinning """""""""""""""""""" Repos can be pinned to a git branch, tag, or commit. .. code-block:: yaml :caption: ``~/.spack/repos.yaml`` :name: code-example-branch repos: builtin: branch: releases/v2025.07 # tag: v2025.07.0 # commit: 6427933daecef74b981d1f773731aeace3b06ede The ``spack repo update`` command will update the repo on disk to match the current state of the config. If the repo is pinned to a commit or tag, it will ensure the repo on disk reflects that commit or tag. If the repo is pinned to a branch or unpinned, ``spack repo update`` will pull the most recent state of the branch (the default branch if unpinned). Git repositories need a package repo index """""""""""""""""""""""""""""""""""""""""" A single Git repository can contain one or more Spack package repositories. To enable Spack to discover these, the root of the Git repository should contain a ``spack-repo-index.yaml`` file. This file lists the relative paths to package repository roots within the git repo. For example, assume a Git repository at ``https://example.com/my_org/my_pkgs.git`` has the following structure .. code-block:: text my_pkgs.git/ spack-repo-index.yaml # metadata file at the root of the Git repo ... spack_pkgs/ spack_repo/ my_org/ comp_sci_packages/ # package repository for computer science packages repo.yaml packages/ hdf5/ package.py mpich/ package.py physics_packages/ # package repository for physics packages repo.yaml packages/ gromacs/ package.py The ``spack-repo-index.yaml`` in the root of ``https://example.com/my_org/my_pkgs.git`` should look like this: .. code-block:: yaml :caption: ``my_pkgs.git/spack-repo-index.yaml`` :name: code-example-repo-index repo_index: paths: - spack_pkgs/spack_repo/my_org/comp_sci_packages - spack_pkgs/spack_repo/my_org/physics_packages If ``my_pkgs.git`` is configured in ``repos.yaml`` as follows: .. code-block:: yaml :caption: ``~/.spack/repos.yaml`` :name: code-example-git-repo repos: example_mono_repo: https://example.com/my_org/my_pkgs.git Spack will clone ``my_pkgs.git`` and look for ``spack-repo-index.yaml``. It will then register two separate repositories based on the paths found (e.g., ``/spack_pkgs/spack_repo/my_org/comp_sci_packages`` and ``/spack_pkgs/spack_repo/my_org/physics_packages``), each with its own namespace defined in its respective ``repo.yaml`` file. Thus, one ``repos.yaml`` entry for a Git mono-repo can lead to *multiple repositories* being available to Spack. If you want only one of the package repositories from a Git mono-repo, you can override the paths in your user-level ``repos.yaml``. For example, if you only want the computer science packages: .. code-block:: yaml :caption: ``~/.spack/repos.yaml`` :name: code-example-specific-repo repos: example_mono_repo: git: https://example.com/my_org/my_pkgs.git paths: - spack_pkgs/spack_repo/my_org/comp_sci_packages The ``spack repo add`` command can help you set up these configurations easily. The ``builtin`` Repository ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Spack's extensive collection of built-in packages resides at `spack/spack-packages `_. By default, Spack is configured to use this as a Git-based repository. The default configuration in ``$spack/etc/spack/defaults/repos.yaml`` looks something like this: .. code-block:: yaml repos: builtin: git: https://github.com/spack/spack-packages.git .. _namespaces: Namespaces ---------- Every repository in Spack has an associated **namespace** defined in the ``namespace:`` key of its top-level ``repo.yaml`` file. For example, the built-in repository (from ``spack/spack-packages``) has its namespace defined as ``builtin``: .. code-block:: yaml :caption: ``repo.yaml`` of ``spack/spack-packages`` :name: code-example-repo-yaml repo: namespace: builtin api: v2.0 # Or newer Spack records the repository namespace of each installed package. For example, if you install the ``mpich`` package from the ``builtin`` repo, Spack records its fully qualified name as ``builtin.mpich``. This accomplishes two things: 1. You can have packages with the same name from different namespaces installed simultaneously. 2. You can easily determine which repository a package came from after it is installed (more :ref:`below `). .. note:: The ``namespace`` defined in the package repository's ``repo.yaml`` is the **authoritative source** for the namespace. It is *not* derived from the local configuration in ``repos.yaml``. This means that the namespace is determined by the repository maintainer, not by the user or local configuration. Nested Namespaces for Organizations ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ As we have already seen in the Git-based package repositories example above, you can create nested namespaces by using periods in the namespace name. For example, a repository for packages related to computation at LLNL might have the namespace ``llnl.comp``, while one for physical and life sciences could be ``llnl.pls``. On the file system, this requires a directory structure like this: .. code-block:: text /path/to/repos/ spack_repo/ llnl/ comp/ repo.yaml # Contains namespace: llnl.comp packages/ mpich/ package.py pls/ repo.yaml # Contains namespace: llnl.pls packages/ hdf5/ package.py Uniqueness ^^^^^^^^^^ Spack cannot ensure global uniqueness of all namespaces, but it will prevent you from registering two repositories with the same namespace *at the same time* in your current configuration. If you try to add a repository that has the same namespace as an already registered one, Spack will print a warning and may ignore the new addition or apply specific override logic depending on the configuration. .. _namespace-example: Namespace Example ^^^^^^^^^^^^^^^^^ Suppose LLNL maintains its own version of ``mpich`` (in a repository with namespace ``llnl.comp``), separate from Spack's built-in ``mpich`` package (namespace ``builtin``). If you've installed both, ``spack find`` alone might be ambiguous: .. code-block:: console $ spack find ==> 2 installed packages. -- linux-rhel6-x86_64 / gcc@4.4.7 ------------- mpich@3.2 mpich@3.2 Using ``spack find -N`` displays packages with their namespaces: .. code-block:: console $ spack find -N ==> 2 installed packages. -- linux-rhel6-x86_64 / gcc@4.4.7 ------------- builtin.mpich@3.2 llnl.comp.mpich@3.2 Now you can distinguish them. Packages differing only by namespace will have different hashes: .. code-block:: console $ spack find -lN ==> 2 installed packages. -- linux-rhel6-x86_64 / gcc@4.4.7 ------------- c35p3gc builtin.mpich@3.2 itoqmox llnl.comp.mpich@3.2 All Spack commands that take a package :ref:`spec ` also accept a fully qualified spec with a namespace, allowing you to be specific: .. code-block:: spec $ spack uninstall llnl.comp.mpich Search Order and Overriding Packages ------------------------------------- When Spack resolves an unqualified package name (e.g., ``mpich`` in ``spack install mpich``), it searches the configured repositories in the order they appear in the *merged* ``repos.yaml`` configuration (from highest to lowest precedence scope, and top to bottom within each file). The first repository found that provides the package will be used. For Git-based mono-repos, the individual repositories listed in its ``spack-repo-index.yaml`` are effectively inserted into this search order based on the mono-repo's position. This search order allows you to override built-in packages. If you have your own ``mpich`` in a repository ``my_custom_repo``, and ``my_custom_repo`` is listed before ``builtin`` in your ``repos.yaml``, Spack will use your version of ``mpich`` by default. Suppose your effective (merged) ``repos.yaml`` implies the following order: 1. ``proto`` (local repo at ``~/my_spack_repos/spack_repo/proto_repo``) 2. ``llnl`` (local repo at ``/usr/local/repos/spack_repo/llnl_repo``) 3. ``builtin`` (Spack's default packages from ``spack/spack-packages``) And the packages are: +--------------+------------------------------------------------+-----------------------------+ | Namespace | Source | Packages | +==============+================================================+=============================+ | ``proto`` | ``~/my_spack_repos/spack_repo/proto_repo`` | ``mpich`` | +--------------+------------------------------------------------+-----------------------------+ | ``llnl`` | ``/usr/local/repos/spack_repo/llnl_repo`` | ``hdf5`` | +--------------+------------------------------------------------+-----------------------------+ | ``builtin`` | `spack/spack-packages` (Git) | ``mpich``, ``hdf5``, others | +--------------+------------------------------------------------+-----------------------------+ If ``hdf5`` depends on ``mpich``: * ``spack install hdf5`` will install ``llnl.hdf5 ^proto.mpich``. Spack finds ``hdf5`` first in ``llnl``. For its dependency ``mpich``, Spack searches again from the top, finding ``mpich`` first in ``proto``. You can force a particular repository's package using a fully qualified name: * ``spack install hdf5 ^builtin.mpich`` will install ``llnl.hdf5 ^builtin.mpich``. * ``spack install builtin.hdf5 ^builtin.mpich`` will install ``builtin.hdf5 ^builtin.mpich``. To see which repositories will be used for a build *before* installing, use ``spack spec -N``: .. code-block:: spec $ spack spec -N hdf5 llnl.hdf5@1.10.0 ^proto.mpich@3.2 ^builtin.zlib@1.2.8 .. warning:: While you *can* use a fully qualified package name in a ``depends_on`` directive within a ``package.py`` file (e.g., ``depends_on("proto.hdf5")``), this is **strongly discouraged**. It makes the package non-portable and tightly coupled to a specific repository configuration, hindering sharing and composition of repositories. A package will fail to load if the hardcoded namespace's repository is not registered. .. _cmd-spack-repo: The ``spack repo`` Command -------------------------- Spack provides commands to manage your repository configurations. .. _cmd-spack-repo-list: ``spack repo list`` ^^^^^^^^^^^^^^^^^^^^^^ This command shows all repositories Spack currently knows about, including their namespace, API version, and resolved path (local path or clone directory for Git repos). .. code-block:: console $ spack repo list [+] my_local v2.0 /path/to/spack_repo/my_local_packages [+] comp_sci_packages v2.0 ~/.spack/package_repos//spack_pkgs/spack_repo/comp_sci_packages [+] physics_packages v2.0 ~/.spack/package_repos//spack_pkgs/spack_repo/physics_packages # From the same git repo [+] builtin v2.0 ~/.spack/package_repos//repos/spack_repo/builtin Spack shows a green ``[+]`` next to each repository that is available for use. It shows a red ``[-]`` to indicate that package repositories cannot be used due to an error (e.g., unsupported API version, missing ``repo.yaml``, etc.). It can also show just a gray ``-`` if it is a Git-based package repository that has not been cloned yet. Note that for Git-based package repositories, ``spack repo list`` will show entries for *each* individual package repository registered via ``spack-repo-index.yaml``. This contrasts with ``spack config get repos``, which shows the raw configuration from ``repos.yaml`` files, including just the Git URL for a mono-repo: .. code-block:: console $ spack config get repos repos: my_local_packages: /path/to/spack_repo/my_local_packages example_mono_repo: https://example.com/my_org/my_pkgs.git # contains two package repositories builtin: git: https://github.com/spack/spack-packages.git # destination: /my/custom/path (if set by user) .. _cmd-spack-repo-create: ``spack repo create`` ^^^^^^^^^^^^^^^^^^^^^ To create the directory structure for a new, empty local repository: .. code-block:: console $ spack repo create ~/my_spack_projects myorg.projectx ==> Created repo with namespace 'myorg.projectx'. ==> To register it with spack, run this command: spack repo add ~/my_spack_projects/spack_repo/myorg/projectx This command creates the following structure: .. code-block:: text ~/my_spack_projects/ spack_repo/ myorg/ projectx/ repo.yaml # Contains namespace: myorg.projectx packages/ # Empty directory for new package.py files The ```` is where the ``spack_repo/`` hierarchy will be created. The ```` can be simple (e.g., ``myrepo``) or nested (e.g., ``myorg.projectx``), and Spack will create the corresponding directory structure. .. _cmd-spack-repo-add: ``spack repo add`` ^^^^^^^^^^^^^^^^^^ To register package repositories from local paths or a remote Git repositories with Spack: * **For a local path:** Provide the path to the repository's root directory (the one containing ``repo.yaml`` and ``packages/``). .. code-block:: console $ spack repo add ~/my_spack_projects/spack_repo/myorg/projectx ==> Added repo to config with name 'myorg.projectx'. * **For a Git repository:** Provide the Git URL. .. code-block:: console $ spack repo add --name my_pkgs https://github.com/spack/spack-packages.git ~/my_pkgs Cloning into '/home/user/my_pkgs'... ==> Added repo to config with name 'my_pkgs'. Notice that for Git-based package repositories, you need to specify a configuration name explicitly, which is the key used in your ``repos.yaml`` configuration file. The example also shows providing a custom destination path ``~/my_pkgs``. You can omit this if you want Spack to use the default clone location (e.g., ``~/.spack/package_repos/``). After adding, packages from this repository should appear in ``spack list`` and be installable. .. _cmd-spack-repo-remove: ``spack repo remove`` ^^^^^^^^^^^^^^^^^^^^^ To unregister a repository, use its configuration name (the key in ``repos.yaml``) or its local path. By configuration name (e.g., ``projectx`` from the add example): .. code-block:: console $ spack repo remove projectx ==> Removed repository 'projectx'. By path (for a local repo): .. code-block:: console $ spack repo remove ~/my_spack_projects/spack_repo/myorg/projectx ==> Removed repository '/home/user/my_spack_projects/spack_repo/myorg/projectx'. This command removes the corresponding entry from your ``repos.yaml`` configuration. It does *not* delete the local repository files or any cloned Git repositories. .. _cmd-spack-repo-set-destination: ``spack repo set`` ^^^^^^^^^^^^^^^^^^ For Git-based repositories, this command allows you to specify a custom local directory where Spack should clone the repository, or use an existing clone. The ```` is the key used in your ``repos.yaml`` file for that Git repository (e.g., ``builtin``, ``my_remote_repo``). .. code-block:: console $ spack repo set --destination /my/custom/path/for/spack-packages builtin ==> Updated repo 'builtin' This updates your user-level ``repos.yaml``, adding or modifying the ``destination:`` key for the specified repository configuration name. .. code-block:: yaml :caption: ``~/.spack/repos.yaml`` after ``spack repo set`` :name: code-example-specific-destination repos: builtin: destination: /my/custom/path/for/spack-packages # The 'git:' URL is typically inherited from Spack's default configuration for 'builtin' Spack will then use ``/my/custom/path/for/spack-packages`` for the ``builtin`` repository. If the directory doesn't exist, Spack will clone into it. If it exists and is a valid Git repository, Spack will use it. Repository Namespaces and Python -------------------------------- Package repositories in Spack (from ``api: v2.0`` or newer) are structured to integrate smoothly with Python's import system. They are effectively Python namespace packages under the top-level ``spack_repo`` namespace. The ``api: v2.0`` repository structure ensures that packages can be imported using a standard Python module path: ``spack_repo..packages..package``. For instance, the ``mpich`` package from the ``builtin`` repository corresponds to the Python module ``spack_repo.builtin.packages.mpich.package``. This allows you to easily extend or subclass package classes from other repositories in your own ``package.py`` files: .. code-block:: python # In a package file (e.g. my_custom_mpich/package.py) in your custom repo # Import the original Mpich class from the 'builtin' repository from spack_repo.builtin.packages.mpich.package import Mpich as BuiltinMpich class MyCustomMpich(BuiltinMpich): # Override versions, variants, or methods from BuiltinMpich version("3.5-custom", sha256="...") # Add a new variant variant("custom_feature", default=False, description="Enable my custom feature") def install(self, spec, prefix): if "+custom_feature" in spec: # Do custom things pass super().install(spec, prefix) # Call parent install method Spack manages Python's ``sys.path`` at runtime to make these imports discoverable across all registered repositories. This capability is powerful for creating derivative packages or slightly modifying existing ones without copying entire package files.