Profiles
Profiles provide a way to alter the compiler settings, influencing things likeoptimizations and debugging symbols.
Cargo has 4 built-in profiles:dev,release,test, andbench. Theprofile is automatically chosen based on which command is being run if aprofile is not specified on the command-line. In addition to the built-inprofiles, custom user-defined profiles can also be specified.
Profile settings can be changed inCargo.toml with the[profile] table. Within each named profile, individual settings can be changedwith key/value pairs like this:
[profile.dev]opt-level = 1 # Use slightly better optimizations.overflow-checks = false # Disable integer overflow checks.Cargo only looks at the profile settings in theCargo.toml manifest at theroot of the workspace. Profile settings defined in dependencies will beignored.
Additionally, profiles can be overridden from aconfig definition.Specifying a profile in a config file or environment variable will overridethe settings fromCargo.toml.
Profile settings
The following is a list of settings that can be controlled in a profile.
opt-level
Theopt-level setting controls the-C opt-level flag which controls the levelof optimization. Higher optimization levels may produce faster runtime code atthe expense of longer compiler times. Higher levels may also change andrearrange the compiled code which may make it harder to use with a debugger.
The valid options are:
0: no optimizations1: basic optimizations2: some optimizations3: all optimizations"s": optimize for binary size"z": optimize for binary size, but also turn off loop vectorization.
It is recommended to experiment with different levels to find the rightbalance for your project. There may be surprising results, such as level3being slower than2, or the"s" and"z" levels not being necessarilysmaller. You may also want to reevaluate your settings over time as newerversions ofrustc change optimization behavior.
See alsoProfile Guided Optimization for more advanced optimizationtechniques.
debug
Thedebug setting controls the-C debuginfo flag which controls theamount of debug information included in the compiled binary.
The valid options are:
0,false, or"none": no debug info at all, default forrelease"line-directives-only": line info directives only. For the nvptx* targets this enablesprofiling. For other use cases,line-tables-onlyis the better, more compatible choice."line-tables-only": line tables only. Generates the minimal amount of debug info for backtraces with filename/line number info, but not anything else, i.e. no variable or function parameter info.1or"limited": debug info without type or variable-level information. Generates more detailed module-level info thanline-tables-only.2,true, or"full": full debug info, default fordev
For more information on what each option does seerustc’s docs ondebuginfo.
You may wish to also configure thesplit-debuginfo optiondepending on your needs as well.
MSRV: 1.71 is required for
none,limited,full,line-directives-only, andline-tables-only
split-debuginfo
Thesplit-debuginfo setting controls the-C split-debuginfo flag whichcontrols whether debug information, if generated, is either placed in theexecutable itself or adjacent to it.
This option is a string and acceptable values are the same as those thecompiler accepts. The default value for this optionisunpacked on macOS for profiles that have debug information otherwiseenabled. Otherwise the default for this option isdocumented with rustc and is platform-specific. Some options are onlyavailable on thenightly channel. The Cargo default may change in the futureonce more testing has been performed, and support for DWARF is stabilized.
Be aware that Cargo and rustc have different defaults for this option. Thisoption exists to allow Cargo to experiment on different combinations of flagsthus providing better debugging and developer experience.
strip
Thestrip option controls the-C strip flag, which directs rustc tostrip either symbols or debuginfo from a binary. This can be enabled like so:
[package]# ...[profile.release]strip = "debuginfo"Possible string values ofstrip are"none","debuginfo", and"symbols".The default is"none".
You can also configure this option with the boolean valuestrue orfalse.strip = true is equivalent tostrip = "symbols".strip = false isequivalent tostrip = "none" and disablesstrip completely.
debug-assertions
Thedebug-assertions setting controls the-C debug-assertions flag whichturnscfg(debug_assertions)conditional compilation on or off. Debugassertions are intended to include runtime validation which is only availablein debug/development builds. These may be things that are too expensive orotherwise undesirable in a release build. Debug assertions enables thedebug_assert! macro in the standard library.
The valid options are:
true: enabledfalse: disabled
overflow-checks
Theoverflow-checks setting controls the-C overflow-checks flag whichcontrols the behavior ofruntime integer overflow. When overflow-checks areenabled, a panic will occur on overflow.
The valid options are:
true: enabledfalse: disabled
lto
Thelto setting controlsrustc’s-C lto,-C linker-plugin-lto, and-C embed-bitcode options, which control LLVM’slink time optimizations.LTO can produce better optimized code, using whole-program analysis, at the costof longer linking time.
The valid options are:
trueor"fat": Performs “fat” LTO which attempts to performoptimizations across all crates within the dependency graph."thin": Performs“thin” LTO. This is similar to “fat”, but takessubstantially less time to run while still achieving performance gainssimilar to “fat”.false: Performs “thin local LTO” which performs “thin” LTO on the localcrate only across itscodegen units. No LTO is performedif codegen units is 1 oropt-level is 0."off": Disables LTO.
See thelinker-plugin-lto chapter if you are interested in cross-language LTO.This is not yet supported natively in Cargo, but can be performed viaRUSTFLAGS.
panic
Thepanic setting controls the-C panic flag which controls which panicstrategy to use.
The valid options are:
"unwind": Unwind the stack upon panic."abort": Terminate the process upon panic.
When set to"unwind", the actual value depends on the default of the targetplatform. For example, the NVPTX platform does not support unwinding, so italways uses"abort".
Tests, benchmarks, build scripts, and proc macros ignore thepanic setting.Therustc test harness currently requiresunwind behavior. See thepanic-abort-tests unstable flag which enablesabort behavior.
Additionally, when using theabort strategy and building a test, all of thedependencies will also be forced to build with theunwind strategy.
incremental
Theincremental setting controls the-C incremental flag which controlswhether or not incremental compilation is enabled. Incremental compilationcausesrustc to save additional information to disk which will be reusedwhen recompiling the crate, improving re-compile times. The additionalinformation is stored in thetarget directory.
The valid options are:
true: enabledfalse: disabled
Incremental compilation is only used for workspace members and “path”dependencies.
The incremental value can be overridden globally with theCARGO_INCREMENTALenvironment variable or thebuild.incremental config variable.
codegen-units
Thecodegen-units setting controls the-C codegen-units flag whichcontrols how many “code generation units” a crate will be split into. Morecode generation units allows more of a crate to be processed in parallelpossibly reducing compile time, but may produce slower code.
This option takes an integer greater than 0.
The default is 256 forincremental builds, and 16 fornon-incremental builds.
rpath
Therpath setting controls the-C rpath flag which controlswhether or notrpath is enabled.
Default profiles
dev
Thedev profile is used for normal development and debugging. It is thedefault for build commands likecargo build, and is used forcargo install --debug.
The default settings for thedev profile are:
[profile.dev]opt-level = 0debug = truesplit-debuginfo = '...' # Platform-specific.strip = "none"debug-assertions = trueoverflow-checks = truelto = falsepanic = 'unwind'incremental = truecodegen-units = 256rpath = falserelease
Therelease profile is intended for optimized artifacts used for releasesand in production. This profile is used when the--release flag is used, andis the default forcargo install.
The default settings for therelease profile are:
[profile.release]opt-level = 3debug = falsesplit-debuginfo = '...' # Platform-specific.strip = "none"debug-assertions = falseoverflow-checks = falselto = falsepanic = 'unwind'incremental = falsecodegen-units = 16rpath = falsetest
Thetest profile is the default profile used bycargo test.Thetest profile inherits the settings from thedev profile.
bench
Thebench profile is the default profile used bycargo bench.Thebench profile inherits the settings from therelease profile.
Build Dependencies
To compile quickly, all profiles, by default, do not optimize builddependencies (build scripts, proc macros, and their dependencies), and avoidcomputing debug info when a build dependency is not used as a runtimedependency. The default settings for build overrides are:
[profile.dev.build-override]opt-level = 0codegen-units = 256debug = false # when possible[profile.release.build-override]opt-level = 0codegen-units = 256However, if errors occur while running build dependencies, turning full debuginfo on will improve backtraces and debuggability when needed:
debug = trueBuild dependencies otherwise inherit settings from the active profile in use, asdescribed inProfile selection.
Custom profiles
In addition to the built-in profiles, additional custom profiles can bedefined. These may be useful for setting up multiple workflows and buildmodes. When defining a custom profile, you must specify theinherits key tospecify which profile the custom profile inherits settings from when thesetting is not specified.
For example, let’s say you want to compare a normal release build with arelease build withLTO optimizations, you can specify something likethe following inCargo.toml:
[profile.release-lto]inherits = "release"lto = trueThe--profile flag can then be used to choose this custom profile:
cargo build --profile release-ltoThe output for each profile will be placed in a directory of the same nameas the profile in thetarget directory. As in the example above, theoutput would go into thetarget/release-lto directory.
Profile selection
The profile used depends on the command, the command-line flags like--release or--profile, and the package (in the case ofoverrides). The default profile if none is specified is:
| Command | Default Profile |
|---|---|
cargo run,cargo build,cargo check,cargo rustc | dev profile |
cargo test | test profile |
cargo bench | bench profile |
cargo install | release profile |
You can switch to a different profile using the--profile=NAME option which will used the given profile.The--release flag is equivalent to--profile=release.
The selected profile applies to all Cargo targets,includinglibrary,binary,example,test,andbenchmark.
The profile for specific packages can be specified withoverrides, described below.
Overrides
Profile settings can be overridden for specific packages and build-timecrates. To override the settings for a specific package, use thepackagetable to change the settings for the named package:
# The `foo` package will use the -Copt-level=3 flag.[profile.dev.package.foo]opt-level = 3The package name is actually aPackage ID Spec, so you cantarget individual versions of a package with syntax such as[profile.dev.package."foo:2.1.0"].
To override the settings for all dependencies (but not any workspace member),use the"*" package name:
# Set the default for dependencies.[profile.dev.package."*"]opt-level = 2To override the settings for build scripts, proc macros, and theirdependencies, use thebuild-override table:
# Set the settings for build scripts and proc-macros.[profile.dev.build-override]opt-level = 3Note: When a dependency is both a normal dependency and a build dependency,Cargo will try to only build it once when
--targetis not specified. Whenusingbuild-override, the dependency may need to be built twice, once as anormal dependency and once with the overridden build settings. This mayincrease initial build times.
The precedence for which value is used is done in the following order (firstmatch wins):
[profile.dev.package.name]— A named package.[profile.dev.package."*"]— For any non-workspace member.[profile.dev.build-override]— Only for build scripts, proc macros, andtheir dependencies.[profile.dev]— Settings inCargo.toml.- Default values built-in to Cargo.
Overrides cannot specify thepanic,lto, orrpath settings.
Overrides and generics
The location where generic code is instantiated will influence theoptimization settings used for that generic code. This can cause subtleinteractions when using profile overrides to change the optimization level ofa specific crate. If you attempt to raise the optimization level of adependency which defines generic functions, those generic functions may not beoptimized when used in your local crate. This is because the code may begenerated in the crate where it is instantiated, and thus may use theoptimization settings of that crate.
For example,nalgebra is a library which defines vectors and matrices makingheavy use of generic parameters. If your local code defines concrete nalgebratypes likeVector4<f64> and uses their methods, the corresponding nalgebracode will be instantiated and built within your crate. Thus, if you attempt toincrease the optimization level ofnalgebra using a profile override, it maynot result in faster performance.
Further complicating the issue,rustc has some optimizations where it willattempt to share monomorphized generics between crates. If the opt-level is 2or 3, then a crate will not use monomorphized generics from other crates, norwill it export locally defined monomorphized items to be shared with othercrates. When experimenting with optimizing dependencies for development,consider trying opt-level 1, which will apply some optimizations while stillallowing monomorphized items to be shared.