v1.0.0
is a major feature release and a significant milestone. It introduces compiler dependencies, a foundational change that has been in development for almost seven years, and the project’s first stable package API.
If you are interested in more information, you can find more details on the road to v1.0, as well as its features, in talks from the 2025 Spack User Meeting. For example:
Introducing some of these features required us to make breaking changes. In most cases, we’ve also provided tools (in the form of Spack commands) that you can use to automatically migrate your packages and configuration.
Overview
- Overview
- Stable Package API
- Compiler dependencies
- Additional Major Features
- New commands and options
- Notable refactors
- Documentation
- Notable Bugfixes
- Additional deprecations, removals, and breaking changes
- Spack community stats
Stable Package API
In Spack v1.0
, the package repository is separate from the Spack tool, giving you more control over the versioning of package recipes. There is also a stable Package API that is versioned separately from Spack.
This release of Spack supports package API from v1.0
up to v2.2
. The older v1.0
package API is deprecated and may be removed in a future release, but we are guaranteeing that any Spack v1.x
release will be backward compatible with Package API v.2.x
– i.e., it can execute code from the packages in this Spack release.
See the Package API Documentation for full details on package versioning and compatibility. The high level details are:
- The
spack.package
Python module defines the Package API; - The Package API minor version is incremented when new functions or classes are exported from
spack.package
; and - The major version is incremented when functions or classes are removed or have breaking changes to their signatures (a rare occurrence).
This independent versioning allows package authors to utilize new Spack features without waiting for a new Spack release. Older Spack packages (API v1.0
) may import code from outside of spack.package
, e.g., from spack.*
or llnl.util.*
. This is deprecated and not included in the API guarantee. We will remove support for these packages in a future Spack release.
Separate Package Repository
The Spack builtin
package repository no longer lives in the Spack git repository. You can find it here:
- https://github.com/spack/spack-packages
Spack clones the package repository automatically when you first run, so you do not have to manage this manually. By default, Spack version v1.0
uses the v2025.07
release of spack-packages
. You can find out more about it by looking at the package releases.
Downloaded package repos are stored by default within ~/.spack
, but the fetch destination can be configured. (#50650). If you want your package repository to live somewhere else, run, e.g.:
spack repo set --destination ~/spack-packages builtin
You can also configure your own package repositories to be fetched automatically from git urls, just as you can with builtin
. See the repository configuration docs for details.
Updating and Pinning Packages
You can tell Spack to update the core package repository from a branch. For example, on develop
or on a release, you can run commands like:
# pull the latest packages
spack repo update
or
# check out a specific commit of the spack-packages repo
spack repo update --commit 2bf4ab9585c8d483cc8581d65912703d3f020393 builtin
which will set up your configuration like this:
repos:
builtin:
git: "https://github.com/spack/spack-packages.git"
commit: 2bf4ab9585c8d483cc8581d65912703d3f020393
You can use this within an environment to pin a specific version of its package files. See the repository configuration docs for more details (#50868, #50997, #51021).
Breaking changes related to package repositories
-
The builtin repo now lives in
var/spack/repos/spack_repo/builtin
instead ofvar/spack/repos/builtin
, and it has a new layout, which you can learn about in the repo docs. -
The module
spack.package
no longer exports the following symbols, mostly related to build systems:AspellDictPackage
,AutotoolsPackage
,BundlePackage
,CachedCMakePackage
,cmake_cache_filepath
,cmake_cache_option
,cmake_cache_path
,cmake_cache_string
,CargoPackage
,CMakePackage
,generator
,CompilerPackage
,CudaPackage
,Package
,GNUMirrorPackage
,GoPackage
,IntelPackage
,IntelOneApiLibraryPackageWithSdk
,IntelOneApiLibraryPackage
,IntelOneApiStaticLibraryList
,IntelOneApiPackage
,INTEL_MATH_LIBRARIES
,LuaPackage
,MakefilePackage
,MavenPackage
,MesonPackage
,MSBuildPackage
,NMakePackage
,OctavePackage
,PerlPackage
,PythonExtension
,PythonPackage
,QMakePackage
,RacketPackage
,RPackage
,ROCmPackage
,RubyPackage
,SConsPackage
,SIPPackage
,SourceforgePackage
,SourcewarePackage
,WafPackage
,XorgPackage
These are now part of the
builtin
package repository, not part of core spack or its package API. When using repositories with package APIv2.0
and higher, you must explicitly import these package classes from the appropriate module inspack_repo.builtin.build_systems
(see #50452 for more).e.g., for
CMakePackage
, you would write:from spack_repo.builtin.build_systems.cmake import CMakePackage
Note that
GenericBuilder
andPackage
are part of the core package API. They are currently re-exported fromspack_repo.builtin.build_systems.generic
for backward compatibility but may be removed from the package repo. You should prefer to import them fromspack.package
.The original names will still work for old-style (
v1.0
) package repositories but not inv2.0
package repositories. Note that this means that the API stability promise does not include old-style package repositories. They are deprecated and will be removed in a future version. So, you should update as soon as you can. -
Package directory names within
v2.0
repositories are now valid Python modulesOld New Description py-numpy/package.py
py_numpy/package.py
hyphen is replaced by underscore. 7zip/package.py
_7zip/package.py
leading digits now preceded by _ pass/package.py
_pass/package.py
Python reserved words preceded by _ -
Spack has historically injected
import
statements into package recipes, so there was no need to usefrom spack.package import *
(though we have included it inbuiltin
packages for years.from spack.package import *
(or more specific imports) will be necessary in packages. The magic we added in the early days of Spack was causing IDEs, code editors, and other tools not to be able to understand Spack packages. Now they use standard Python import semantics and should be compatible with modern Python tooling. This change was also necessary to support Python 3.13. (see #47947 for more details).
Migrating to the new package API
Support will remain in place for the old repository layout for at least a year, so that you can continue to use old-style repos in conjunction with earlier versions. If you have custom repositories that need to migrate to the new layout, you can upgrade them to package API v2.x
by running:
spack repo migrate
This will make the following changes to your repository:
-
If you used to import from
spack.pkg.builtin
in Python, you now need to import fromspack_repo.builtin
instead:# OLD: no longer supported from spack.pkg.builtin.my_pkg import MyPackage # NEW: spack_repo is a Python namespace package from spack_repo.builtin.packages.my_pkg.package import MyPackage
- Normalized directory names for packages
- New-style
spack.package
imports
See #50507, #50579, and #50594 for more.
Compiler dependencies
Prior to v1.0
, compilers in Spack were attributes on nodes in the spec graph, with a name and a version (e.g., gcc@12.0.0
). In v1.0
compilers are packages like any other package in Spack (see #45189). This means that they can have variants, targets, and other attributes that regular nodes have.
Here, we list the major changes that users should be aware of for this new model.
Compiler configuration
In Spack v1.0
, compilers.yaml
is deprecated. compilers.yaml
is still read by Spack, if present. We will continue to support this for at least a year, but we may remove it after that. Users are encouraged to migrate their configuration to use packages.yaml
instead.
Old style compilers.yaml
specification:
compilers:
- compiler:
spec: gcc@12.3.1
paths:
c: /usr/bin/gcc
cxx: /usr/bin/g++
fc: /usr/bin/gfortran
modules: [...]
New style packages.yaml
compiler specification:
packages:
gcc:
externals:
- spec: gcc@12.3.1+binutils
prefix: /usr
extra_attributes:
compilers:
c: /usr/bin/gcc
cxx: /usr/bin/g++
fc: /usr/bin/gfortran
modules: [...]
See Configuring Compilers for more details.
Languages are virtual dependencies
Packages that need a C, C++, or Fortran compiler now must depend on c
, cxx
, or fortran
as a build dependency, e.g.:
class MyPackage(Package):
depends_on("c", type="build")
depends_on("cxx", type="build")
depends_on("fortran", type="build")
Historically, Spack assumed that every package was compiled with C, C++, and Fortran. In Spack v1.0
, we allow packages to simply not have a compiler if they do not need one. For example, pure Python packages would not depend on any of these, and you should not add these dependencies to packages that do not need them.
Spack v0.23
introduced language virtual dependencies, and we have back-ported them to 0.21.3
and v0.22.2
. In pre-1.0 Spack releases, these are a no-op. They are present so that language dependencies do not cause an error. This allows you to more easily use older Spack versions together with v1.0
.
See #45217 for more details.
The meaning of %
has changed
In Spack v0.x
, %
specified a compiler with a name and an optional version. In Spack v1.0
, it simply means “direct dependency”. It is similar to the caret ^
, which means “direct or transitive dependency”.
Unlike ^
, which specifies a dependency that needs to be unified for the whole graph, %
can specify direct dependencies of particular nodes. This means you can use it to mix and match compilers, or cmake
versions, or any other package for which multiple versions of the same build dependency are needed in the same graph. For example, in this spec:
foo ^hdf5 %cmake@3.1.2 ^zlib-ng %cmake@3.2.4
hdf5
and zlib-ng
are both transitive dependencies of foo
, but hdf5
will be built with cmake@3.1.2
and zlib-ng
will be built with %cmake@3.2.4
. This is similar to mixing compilers, but you can now use %
with other types of build dependencies, as well. You can have multiple versions of packages in the same graph, as long as they are purely build dependencies.
Virtual assignment syntax
You can still specify compilers with foo %gcc
, in which case gcc
will be used to satisfy any c
, cxx
, and fortran
dependencies of foo
, but you can also be specific about the compiler that should be used for each language. To mix, e.g., clang
and gfortran
, you can now use virtual assignment like so:
spack install foo %c,cxx=gcc %fortran=gfortran
This says to use gcc
for c
and cxx
, and gfortran
for fortran
.
It is functionally equivalent to the already supported edge attribute syntax:
spack install foo %[virtuals=c,cxx] gcc %[virtuals=fortran] gfortran
But, virtual assignment is more legible. We use it as the default formatting for virtual edge attributes, and we print it in the output of spack spec
, spack find
, etc. For example:
> spack spec zlib
- zlib@1.3.1+optimize+pic+shared build_system=makefile arch=darwin-sequoia-m1 %c,cxx=apple-clang@16.0.0
[e] ^apple-clang@16.0.0 build_system=bundle arch=darwin-sequoia-m1
- ^compiler-wrapper@1.0 build_system=generic arch=darwin-sequoia-m1
[+] ^gmake@4.4.1~guile build_system=generic arch=darwin-sequoia-m1 %c=apple-clang@16.0.0
[+] ^compiler-wrapper@1.0 build_system=generic arch=darwin-sequoia-m1
You can see above that only zlib
and gmake
are compiled, and gmake
uses only c
. The other nodes are either external, and we cannot detect the compiler (apple-clang
) or they are not compiled (compiler-wrapper
is a shell script).
Toolchains
Spack now has a concept of a “toolchain”, which can be configured in toolchains.yaml
. A toolchain is an alias for common dependencies, flags, and other spec properties that you can attach to a node in a graph with %
.
Toolchains are versatile and composable as they are simply aliases for regular specs. You can use them to represent mixed compiler combinations, compiler/MPI/numerical library groups, particular runtime libraries, and flags – all to be applied together. This allows you to do with compiler dependencies what we used to do with compilers.yaml
, and more.
Example mixed clang/gfortran toolchain:
toolchains:
clang_gfortran:
- spec: %c=clang
when: %c
- spec: %cxx=clang
when: %cxx
- spec: %fortran=gcc
when: %fortran
- spec: cflags="-O3 -g"
- spec: cxxflags="-O3 -g"
- spec: fflags="-O3 -g"
This enables you to write spack install foo %clang_gfortran
, and Spack will resolve the %clang_gfortran
toolchain to include the dependencies and flags listed in toolchains.yaml
.
You could also couple the intel compilers with mvapich2
like so:
toolchains:
intel_mvapich2:
- spec: %c=intel-oneapi-compilers @2025.1.1
when: %c
- spec: %cxx=intel-oneapi-compilers @2025.1.1
when: %cxx
- spec: %fortran=intel-oneapi-compilers @2025.1.1
when: %fortran
- spec: %mpi=mvapich2 @2.3.7-1 +cuda
when: %mpi
The when:
conditions here ensure that toolchain constraints are only applied when needed. See the toolchains documentation or #50481 for details.
Ordering of variants and compilers now matters
In Spack v0.x
, these two specs parse the same:
pkg %gcc +foo
pkg +foo %gcc
The +foo
variant applies to pkg
in either case. In Spack v1.0
, there is a breaking change, and +foo
in pkg %gcc +foo
now applies to gcc
, since gcc
is a normal package. This ensures we have the following symmetry:
pkg +foo %dep +bar # `pkg +foo` depends on `dep +bar` directly
pkg +foo ^dep +bar # `pkg +foo` depends on `dep +bar` directly or transitively
In Spack v1.0
you may get errors at concretization time if +foo
is not a variant of gcc
in specs like%pkg %gcc +foo
.
You can use the spack style --spec-strings
command to update package.py
files, spack.yaml
files:
# dry run
spack style --spec-strings $(git ls-files) # if you have a git repo
spack style --spec-strings spack.yaml # environments
# use --fix to perform the changes listed by the dry run
spack style --fix --spec-strings $(git ls-files)
spack style --fix --spec-strings spack.yaml
See #49808, #49438, #49439 for details.
Additional Major Features
Concurrent Package Builds
This release has completely reworked Spack’s build scheduler, and it adds a -p
/ --concurrent-packages
argument to spack install
, which can greatly accelerate builds with many packages. You can use it in combination with spack install -j
. For example, this command:
spack install -p 4 -j 16
runs up to 4 package builds at once, each with up to 16 make jobs. The default for --concurrent-packages
is currently 1, so you must enable this feature yourself, either on the command line or by setting config:concurrent_packages
(#50856):
config:
concurrent_packages: 1
As before, you can run spack install
on multiple nodes in a cluster, if the filesystem where Spack’s install_tree
is located supports locking.
We will make concurrent package builds the default in 1.1
, when we plan to include support for gmake
’s jobserver protocol and for line-synced output. Currently, setting -p
higher than 1 can make Spack’s output difficult to read.
Content-addressed build caches
Spack v1.0
changes the format of build caches to address a number of scaling and consistency issues with our old (aging) buildcache layout. The new buildcache format is content-addressed and enables us to make many operations atomic (and therefore safer). It is also more extensible than the old buildcache format and can enable features like split debug info and different signing methods in the future. See #48713 for more details.
Spack v1.0
can still read, but not write to, the old build caches. The new build cache format is not backward compatible with the old format, but you can have a new build cache and an old build cache coexist beside each other. If you push to an old build cache, new binaries will start to show up in the new format.
You can migrate an old buildcache to the new format using the spack buildcache migrate
command. It is nondestructive and can migrate an old build cache to a new one in-place. That is, it creates the new buildcache within the same directory, alongside the old buildcache.
As with other major changes, the old buildcache format is deprecated in v1.0
, but will not be removed for at least a year.
Better provenance and mirroring for git
Spack now resolves and preserves the commit of any git-based version at concretization time, storing the precise commit built on the Spec in a reserved commit
variant. This allows us to better reproduce git builds. See #48702 for details.
Historically, Spack has only stored the ref name, e.g. the branch or tag, for git versions that did not already contain full commits. Now we can know exactly what was built regardless of how it was fetched.
As a consequence of this change, mirroring git repositories is also more robust. See #50604, #50906 for details.
Environment variables in environments
You can now specify environment variables in your environment that should be set on activation (and unset on deactivation):
spack:
specs:
- cmake%gcc
env_vars:
set:
MY_FAVORITE_VARIABLE: "TRUE"
The syntax allows the same modifications that are allowed for modules: set:
, unset:
, prepend_path:
, append_path:
, etc.
See [the docs](https://spack.readthedocs.io/en/latest/env_vars_yaml.html or #47587 for more.
Better include functionality
Spack allows you to include local or remote configuration files through include.yaml
, and includes can be optional (i.e. include them only if they exist) or conditional (only include them under certain conditions:
spack:
include:
- /path/to/a/required/config.yaml
- path: /path/to/$os/$target/config
optional: true
- path: /path/to/os-specific/config-dir
when: os == "ventura"
You can use this in an environment, or in an include.yaml
in an existing configuration scope. Included configuration files are required unless they are explicitly optional or the entry’s condition evaluates to false
. Optional includes are specified with the optional
clause and conditional ones with the when
clause.
Conditionals use the same syntax as spec list references The docs on include.yaml
have more information. You can also look at #48784.
New commands and options
spack repo update
will pull the latest packages (#50868, #50997)spack style --spec-strings
fixes old configuration file and packages (#49485)spack repo migrate
: migrates old repositories to the new layout (#50507)spack ci
no longer has a--keep-stage
flag (#49467)- The new
spack config scopes
subcommand will list active configuration scopes (#41455, #50703) spack cd --repo <namespace>
(#50845)spack location --repo <namespace>
(#50845)--force
is now a common argument for all commands that do concretization (#48838)
Notable refactors
- All of Spack is now in one top-level
spack
Python package- The
spack_installable
package is gone as it’s no longer needed (#50996) - The top-level
llnl
package has been moved tospack.llnl
and will likely be refactored more later (#50989) - Vendored dependencies that were previously in
_vendoring
are now inspack.vendor
(#51005)
- The
- Increased determinism when generating inputs for the ASP solver, leading to more consistent concretization results (#49471)
- Added fast, stable spec comparison, which also increases determinism of concretizer inputs, and more consistent results (#50625)
- Test deps are now part of the DAG hash, so builds with tests enabled will (correctly) have different hashes from builds without tests enabled (#48936)
spack spec
in an environment or on the command line will show unified output with the specs provided as roots (#47574)- users can now set a timeout in
concretizer.yaml
in case they frequently hit long solves (#47661) - GoPackage: respect
-j
` concurrency (#48421) - We are using static analysis to speed up concretization (#48729)
Documentation
We have overhauled a number of sections of the documentation.
- The basics section of the documentation has been reorganized and updated (#50932)
- The packaging guide has been rewritten and broken into four separate, logically ordered sections (#50884).
- As mentioned above the entire
spack.package
API has been documented and consolidated to one package (#51010)
Notable Bugfixes
- A race that would cause timeouts in certain parallel builds has been fixed. Every build now stages its own patches and cannot fight over them (causing a timeout) with other builds (#50697)
- The
command_line
scope is now always the top level. Previously environments could override command line settings (#48255) setup-env.csh
is now hardened to avoid conflicts with user aliases (#49670)
Additional deprecations, removals, and breaking changes
-
spec["pkg"]
searches only direct dependencies and transitive link/run dependencies, ordered by depth. This avoids situations where we pick up unwanted deps of build/test deps. To reach those, you need to dospec["build_dep"]["pkg"]
explicitly (#49016). -
spec["mpi"]
no longer works to refer tospec
itself on specs likeopenmpi
andmpich
that could providempi
. We only find"mpi"
if it is provided by some dependency (see #48984). - We have removed some long-standing internal API methods on
spack.spec.Spec
so that we can decouple internal modules in the Spack code.spack.spec
was including too many different parts of Spack.Spec.concretize()
andSpec.concretized()
have been removed. Usespack.concretize.concretize_one(spec)
instead (#47971, #47978)Spec.is_virtual
` is now spack.repo.PATH.is_virtual (#48986)Spec.virtual_dependencies
has been removed (#49079)
-
#50603: Platform config scopes are now opt-in. If you want to use subdirectories like
darwin
orlinux
in your scopes, you’ll need to include them explicitly in aninclude.yaml
or in yourspack.yaml
file, like so:include: - include: "${platform}" optional: true
-
#48488, #48502: buildcache entries created with Spack 0.19 and older using
spack buildcache create --rel
will no longer be relocated upon install. These old binaries should continue to work, except when they are installed with differentconfig:install_tree:projections
compared to what they were built with. Similarly, buildcache entries created with Spack 0.15 and older that contain long shebang lines wrapped with sbang will no longer be relocated. -
#50462: the
package.py
globalsstd_cmake_args
,std_pip_args
,std_meson_args
were removed. They were deprecated in Spack 0.23. UseCMakeBuilder.std_args(pkg)
,PythonPipBuilder.std_args(pkg)
andMesonBuilder.std_args(pkg)
instead. -
#50605, #50616: If you were using
update_external_dependencies()
in your private packages, note that it is going away in 1.0 to get it out of the package API. It is instead being moved into the concretizer, where it can change in the future, when we have a better way to deal with dependencies of externals, without breaking the package API. We suspect that nobody was doing this, but it’s technically a breaking change. - #48838: Two breaking command changes:
spack install
no longer has a-f
/--file
option – writespack install ./path/to/spec.json
instead.spack mirror create
no longer has a short-f
option – usespack mirror create --file
instead.
-
We no longer support the PGI compilers. They have been replaced by
nvhpc
(#47195) -
Python 3.8 is deprecated in the Python package, as it is EOL (#46913)
- The
target=fe
/target=frontend
andtarget=be
/target=backend
targets from Spack’s orignal compilation model for cross-compiled Cray and BlueGene systems are now deprecated (#47756)
Spack community stats
- 2,276 commits updated package recipes
- 8,499 total packages, 214 new since v0.23.0
- 372 people contributed to this release
- 363 committers to packages
- 63 committers to core</small>View Comment
Version 2025.1.0
is a major release.
Notable Changes
- Display more than 2 metrics on the tree visualization (#165)
- Allows Hatchet to work with NumPy >= 2.0 (#163)
- Remove Extra Aggregation in Timeseries (#164)
- Aggregate on String Attributes (#158)
- Disable Aggregation for non-timeseries Profiles (#157)
Bug Fixes
- Fix Node Ordering Setting (#154)
- Fix sum(nan) == 0 in caliper native reader (#166)
Internal Updates
- Skip HDF Test if Package not Available (#156)
- Update examples to use from_caliperreader by default, instead of from_caliper (#160)
- Update to Ubuntu 22.04 (#159)
- Disables attestations in gh-action-pypi-publish to avoid errors from PyPI (#168)</small>View Comment