Configuration
When is configuration needed?
setuptools-scm provides flexible activation options:
Simplified Activation (No Configuration Needed)
For basic usage, use the simple extra with no configuration:
[build-system]
requires = ["setuptools>=80", "setuptools-scm[simple]>=9.2"]
[project]
dynamic = ["version"]
The [simple] extra enables version inference with default settings.
See the usage guide for details.
Explicit Configuration (Full Control)
Use the [tool.setuptools_scm] section when you need to:
- Write version files (
version_file) - Customize version schemes (
version_scheme,local_scheme) - Set tag matching options (
tag.prefix,tag.strict,tag.regex) - Configure fallback behavior (
fallback_version) - Or any other non-default behavior
Core Configuration
These configuration options control version inference and formatting behavior.
Configuration parameters can be configured in pyproject.toml or setup.py.
Callables or other Python objects must be passed in setup.py (via the use_scm_version keyword argument).
root : Path | PathLike[str]- Relative path to the SCM root, defaults to
.and is relative to the file path passed inrelative_to version_scheme : str | Callable[[ScmVersion], str]- Configures how the version number is constructed; either an entrypoint name or a callable. See Version number construction for predefined implementations.
local_scheme : str | Callable[[ScmVersion], str]- Configures how the local component of the version (the optional part after the
+) is constructed; either an entrypoint name or a callable. See Version number construction for predefined implementations.
Tag Matching Configuration
These options control which VCS tags are considered version tags and how they
are parsed. They are configured under the tag table in pyproject.toml:
[tool.setuptools_scm.tag]
prefix = "" # default – no prefix filtering
strict = true # require tags to contain at least one dot
tag.prefix: str = ""-
A literal prefix that version tags must start with. The prefix is used to filter tags in
git describe --matchand is stripped before version parsing.Use this for monorepos or multi-package repositories where each package has its own tag namespace.
pyproject.toml – monorepo example[tool.setuptools_scm.tag] prefix = "hatchling-v" # matches hatchling-v1.0.0, strips to 1.0.0tag.prefixvalueTags matched Extracted version ""(default)v1.0.0,1.0.0,2026-eventv1.0.0,1.0.0"v"v1.0.0,V1.0.01.0.0"hatchling-v"hatchling-v1.0.01.0.0"py-v"py-v2.3.12.3.1 tag.strict: bool | None = None-
Controls how strictly tags must look like version numbers.
Value Behavior unset ( None)Current permissive matching ( *[0-9]*).trueStrict – tags must contain at least one dot (e.g. *[0-9]*.*[0-9]*). Event-like tags such as2026-eventare rejected.falsePermissive – matches any tag containing a digit ( *[0-9]*).Migration
In a future major release the default will change from permissive to strict. Set
tag.strict = falsenow if you rely on the permissive matching, ortag.strict = trueto adopt the stricter behavior early.While
tag.strictis unset, a warning is logged only if the future default would actually pick a different tag for your repository, naming both the current and the future version. Projects the change cannot affect are never nagged. Silence it withSETUPTOOLS_SCM_DEBUG=ERRORif you cannot act on it, for example when building someone else's project from a checkout.tag.prefixandtag.strictcompose naturally:tag.prefixtag.strictEffective --matchglob""false/ unset*[0-9]*""true*[0-9]*.*[0-9]*"hatchling-v"false/ unsethatchling-v*[0-9]*"hatchling-v"truehatchling-v*[0-9]*.*[0-9]*Mercurial
Mercurial applies the equivalent regex (
\d+/\d+\.\d+, prefixed whentag.prefixis set) both when looking for the latest tag and when the checked-out changeset carries tags of its own. Undertag.strict = truea changeset tagged only with event-style names is treated as untagged, so versioning continues from the last real version tag -- the same thinggit describe --matchdoes.Before setuptools-scm 9 the Mercurial backend always required a dot, so for Mercurial projects the coming strict default restores the historical behavior.
tag.regex: str | Pattern[str]-
A Python regex to extract the version part from a tag after the
tag.prefixhas been stripped. The regex needs a single capture group or a named groupversion.Defaults to vcs_versioning._config.DEFAULT_TAG_REGEX which supports tags with optional "v" prefix, project prefixes, and various version formats.
Tip
Most users should use
tag.prefixandtag.strictinstead of customizing the regex directly. tag_regex(deprecated)-
Deprecated: Use
tag.regexinstead.Top-level
tag_regexis still accepted for backward compatibility but emits aDeprecationWarning. It cannot be used together withtag.regex.
Other Configuration
parentdir_prefix_version: str | None = None-
If the normal methods for detecting the version (SCM version, sdist metadata) fail, and the parent directory name starts with
parentdir_prefix_version, then this prefix is stripped and the rest of the parent directory name is matched withtag_regexto get a version string. If this parameter is unset (the default), then this fallback is not used.This was intended to cover GitHub's "release tarballs", which extract into directories named
projectname-tag/(in which caseparentdir_prefix_versioncan be set e.g. toprojectname-). fallback_version: str | None = None- A version string that will be used if no other method for detecting the
version worked (e.g., when using a tarball with no metadata). If this is
unset (the default),
setuptools-scmwill error if it fails to detect the version. fallback_root: Path | PathLike[str] = "."-
The directory to use when SCM metadata is not available (e.g., in extracted archives like PyPI tarballs). This is particularly useful for legacy configurations that need to work both in development (with SCM metadata) and from archives (without SCM metadata). Defaults to the current directory.
When SCM metadata is present, the
rootparameter is used; when it's not available,fallback_rootis used instead. This allows the same configuration to work in both scenarios without modification. normalize- A boolean flag indicating if the version string should be normalized.
Defaults to
True. Setting this toFalseis equivalent to settingversion_clsto vcs_versioning.NonNormalizedVersion version_cls: type|str = packaging.version.Version-
An optional class used to parse, verify and possibly normalize the version string. Its constructor should receive a single string argument, and its
strshould return the normalized version string to use. This option can also receive a class qualified name as a string.The vcs_versioning.NonNormalizedVersion convenience class is provided to disable the normalization step done by
packaging.version.Version. If this is used whilesetuptools-scmis integrated in a setuptools packaging process, the non-normalized version number will appear in all files (seeversion_filenote).normalization still applies to artifact filenames
Setuptools will still normalize it to create the final distribution, so as to stay compliant with the python packaging standards.
scm.git.describe_command-
This command will be used instead the default
git describe --longcommand.Defaults to the value set by vcs_versioning._backends._git.DEFAULT_DESCRIBE
Overrides tag.strict
When
scm.git.describe_commandis explicitly set, it supplies its own--matchpattern, sotag.stricthas no effect on tag matching. A warning is emitted only if the two would actually select different tags for your repository.tag.prefixis not overridden: it still strips the prefix from the selected tag before version parsing, so combining it with an explicitdescribe_commandis a supported way to bring your own match pattern while keeping prefix stripping. scm.git.pre_parse-
A string specifying which git pre-parse function to use before parsing version information. Available options:
"warn_on_shallow"(default): Warns when the repository is shallow (skipped whenHEADis exactly on a tag, where a shallow clone is sufficient)"fail_on_shallow": Fails with an error when the repository is shallow (not whenHEADis exactly on a tag)"fetch_on_shallow": Automatically fetches to rectify shallow repositories (skipped whenHEADis exactly on a tag)-
"fail_on_missing_submodules": Fails when submodules are defined but not initializedThe
"fail_on_missing_submodules"option is useful to prevent packaging incomplete projects when submodules are required for a complete build.
Note: This setting is overridden by any explicit
pre_parseparameter passed to the git parse function. scm.git.distance_scope-
Restrict the distance count to the commits that touch this project, for projects living in a subdirectory of a monorepo.
false(default): count every commit since the tag, asgit describedoes.true: count only commits touching the project directory.- a list of paths: count commits touching the project directory or any of the listed directories. Paths are relative to the VCS root, not to the project.
[tool.setuptools_scm.scm.git] distance_scope = trueUse the list form for directories the project actually depends on -- shared libraries, generated code, build tooling. Without them, a change to a dependency does not move the project's version even though it changes what gets built:
[tool.setuptools_scm.scm.git] distance_scope = ["shared/common", "tooling"]Requires the project to live below the VCS root; scoping to the root itself would be a no-op and is rejected. Not available for Mercurial, Jujutsu, or hg-git checkouts.
set
tag.prefixwhen projects are tagged separatelygit describepicks the topologically nearest tag, which in a monorepo taggedpkg-a-v1.2,pkg-b-v3.0may well belong to a different project -- and the distance would then be counted from that project's release. A warning is emitted when the reachable tags span several namespaces. Repositories on a single release train (v1.2,v1.3for everything) need no prefix.shallow clones are rejected
A scoped count walks history looking for commits that touch the paths, so a truncated history does not merely shorten the answer -- it can miss every relevant commit and report
0, which reads as an exact tag. This is an error regardless ofscm.git.pre_parse.git archives carry a repository-wide distance
git archiverecords its describe output through%(describe), which takes no pathspec, so an archive of a non-tag commit carries a count that is an upper bound on the scoped one -- the version comes out too high, and a warning says so. An archive of a tag has distance0and is exact either way, so release tarballs are unaffected. Build from an sdist, which carries the already-computed version. scm.git.distance_count-
How commits are counted once
scm.git.distance_scoperestricts them. Ignored whendistance_scopeis not set."full-history"(default): every commit whose content at the scoped paths differs from a parent. Counts work done on merged feature branches, so the numbers can get large in merge-heavy repositories."first-parent": the same, restricted to the first-parent chain, so a merged feature branch counts once no matter how many commits it held. Counts on topic branches are not comparable to mainline's and can decrease when the branch is merged, so use this only if you release from mainline.
Both are set predicates over the commits reachable from
HEADbut not from the tag, so neither can make the distance shrink as mainline history advances. Git's own default history simplification (what plaingit log -- pathshows) is deliberately not offered: it follows only one parent at a merge, which can make the distance shrink. git_describe_command(deprecated)-
Deprecated since 8.4.0: Use
scm.git.describe_commandinstead.This field is maintained for backward compatibility but will issue a deprecation warning when used.
relative_to: Path | PathLike[str] = "pyproject.toml"- A file/directory from which the root can be resolved.
Typically called by a script or module that is not in the root of the
repository to point to the root of the repository by
supplying
__file__. parse: Callable[[Path, Config], ScmVersion] | None = None- A function that will be used instead of the discovered SCM for parsing the version. Use with caution, this is a function for advanced use and you should be familiar with the vcs-versioning internals to use it.
version_file: Path | PathLike[str] | None = None-
A path to a file that gets replaced with a file containing the current version. It is ideal for creating a
_version.pyfile within the package, typically used to avoid usingimportlib.metadata(which adds some overhead).Only files with
.pyand.txtextensions have builtin templates, for other file types it is necessary to provideversion_file_template. version_file_template: str | None = None- A new-style format string taking
version,scm_versionandversion_tupleas parameters.versionis the generated next_version as string,version_tupleis a tuple of split numbers/strings andscm_versionis theScmVersioninstance the currentversionwas rendered from write_to_source: bool | None = None-
Controls whether version files (specified by
version_fileorwrite_to) are written to the source tree during version inference.Value Behavior unset Writes to source tree and emits a DeprecationWarningadvising you to set this option explicitly, since the default will change in a future major release.trueWrites to source tree, no warning — explicit opt-in. falseDoes not write to source tree, no warning — explicit opt-out. Version files are still written to the build directory during build_py.The
SETUPTOOLS_SCM_WRITE_TO_SOURCEenvironment variable overrides this setting (see Environment Variables below).Deprecation cycle
In a future major release, the default will change from writing to source to not writing to source. Set
write_to_source = truenow if you rely on version files being present in your source tree.pyproject.toml[tool.setuptools_scm] version_file = "mypackage/_version.py" write_to_source = true
setuptools-scm Specific Configuration
These options control setuptools integration behavior.
write_to: PathLike[str] | Path | None = None- (deprecated) legacy option to create a version file relative to the SCM root.
It's broken for usage from an sdist and fixing it would be a fatal breaking change,
use
version_fileinstead.
Environment Variables
Version Detection Overrides
These environment variables override version detection behavior.
SETUPTOOLS_SCM_PRETEND_VERSION-
used as the primary source for the version number in which case it will be an unparsed string
it is strongly recommended to use distribution-specific pretend versions (see below).
SETUPTOOLS_SCM_PRETEND_VERSION_FOR_${DIST_NAME}-
used as the primary source for the version number, in which case it will be an unparsed string. Specifying distribution-specific pretend versions will avoid possible collisions with third party distributions also using
setuptools-scmthe dist name normalization follows adapted PEP 503 semantics, with one or more of ".-_" being replaced by a single "_", and the name being upper-cased
this will take precedence over
SETUPTOOLS_SCM_PRETEND_VERSION SETUPTOOLS_SCM_PRETEND_METADATA- A TOML inline table for overriding individual version metadata fields. See the overrides documentation for details.
SETUPTOOLS_SCM_PRETEND_METADATA_FOR_${DIST_NAME}- Same as above but specific to a package (recommended over the generic version).
SETUPTOOLS_SCM_DEBUG- Enable debug logging for version detection and processing.
SOURCE_DATE_EPOCH- Used as the timestamp from which the
node-and-dateandnode-and-timestamplocal parts are derived, otherwise the current time is used. Standard environment variable from reproducible-builds.org.
setuptools-scm Overrides
These environment variables control setuptools-scm specific behavior.
SETUPTOOLS_SCM_IGNORE_VCS_ROOTS- A
os.pathsepseparated list of directory names to ignore for root finding SETUPTOOLS_SCM_HG_COMMAND-
Command used for running Mercurial (defaults to
hg)For example, set this to
chgto reduce start-up overhead of Mercurial SETUPTOOLS_SCM_OVERRIDES_FOR_${DIST_NAME}- A TOML inline table to override configuration from
pyproject.toml. See the overrides documentation for details. SETUPTOOLS_SCM_WRITE_TO_SOURCE- Override the
write_to_sourceconfiguration option. Set to1/true/yesto write version files to the source tree, or0/false/noto disable it. When set, no deprecation warning is emitted regardless of the pyproject.toml setting. SETUPTOOLS_SCM_SUBPROCESS_TIMEOUT- Override the subprocess timeout (default: 40 seconds). See the overrides documentation for details.
SETUPTOOLS_SCM_DISABLE_JJ-
Disable Jujutsu (jj) backend discovery. When set to
1/true/yes, setuptools-scm will skip the jj backend even if a.jj/directory is present, falling back to Git or Mercurial detection instead.This is useful in container or CI environments where a colocated Jujutsu/Git repository is used but the
jjbinary is not installed. Without this variable, a missingjjbinary in a.jj/repository raises an error.Also available as
VCS_VERSIONING_DISABLE_JJ.See Jujutsu repositories for details.
Automatic File Inclusion
Setuptools File Finder Integration
setuptools-scm still registers a setuptools file finder that includes all SCM-tracked files in source distributions. For projects that configure setuptools-scm, file listing uses the validated workdir API instead of this entry point.
Using the global setuptools.file_finders entry point without configuring setuptools-scm is deprecated and will be removed in a future major release. Unconfigured projects that still hit the entry point get a DeprecationWarning.
How it works:
When setuptools-scm is configured, ScmEggInfoMixin lists tracked files from the discovered workdir. The legacy setuptools.file_finders entry point remains registered for compatibility:
- Automatically discovers SCM-managed files (Git, Mercurial, Jujutsu)
- Includes them in source distributions (
python -m build --sdist) - Works for
include_package_data = Truein package building
Entry point registration:
[project.entry-points."setuptools.file_finders"]
setuptools_scm = "setuptools_scm._integration.file_finders:find_files"
Files included by default:
- All files tracked by Git (
git ls-files) - All files tracked by Mercurial (
hg files) - All files tracked by Jujutsu (
jj file list) - Includes: source code, documentation, tests, config files, etc.
- Excludes: untracked files, files in
.gitignore/.hgignore
Controlling inclusion:
Use MANIFEST.in to override the automatic behavior:
# Exclude development files
exclude .pre-commit-config.yaml
exclude tox.ini
global-exclude *.pyc __pycache__/
# Exclude entire directories
prune docs/
prune testing/
# Include non-SCM files
include data/important.json
Debugging file inclusion:
# List files that will be included
python -m setuptools_scm ls
# Build and inspect sdist contents
python -m build --sdist
tar -tzf dist/package-*.tar.gz
Cannot be disabled today
The file finder cannot be turned off through configuration while the entry point is still registered. To stop using it, either configure setuptools-scm (so builds use the workdir path) or remove setuptools-scm from the build environment. The unconfigured entry-point path will be removed in a future major release.
API Reference
constants
vcs_versioning._config.DEFAULT_TAG_REGEX
module-attribute
DEFAULT_TAG_REGEX = compile('^(?:[\\w-]+-)?(?P<version>[vV]?\\d+(?:\\.\\d+){0,2}[^\\+]*)(?:\\+.*)?$')
default tag regex that tries to match PEP440 style versions with prefix consisting of dashed words
vcs_versioning._backends._git.DEFAULT_DESCRIBE
module-attribute
DEFAULT_DESCRIBE = make_describe_command('*[0-9]*')
the configuration class
vcs_versioning.Configuration
dataclass
Global configuration model
Source code in vcs-versioning/src/vcs_versioning/_config.py
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 | |
env
property
env: VcsEnvironment
The :class:~vcs_versioning._environment.VcsEnvironment for this config.
Always non-None after first access — set by VcsEnvironment.build_config()
or lazily resolved on first access (with a DeprecationWarning).
write_to_source
class-attribute
instance-attribute
write_to_source: bool | None = None
Whether to write version files to the source tree at inference time.
None(default): write to source and emit aDeprecationWarningtelling users to set this explicitly, since the default will change in the next major release.True: write to source tree, no warning.False: do not write to source tree, no warning.
The SETUPTOOLS_SCM_WRITE_TO_SOURCE / VCS_VERSIONING_WRITE_TO_SOURCE
environment variable overrides this setting.
discover_workdir
discover_workdir() -> ScmWorkdir | FallbackWorkdir | None
Discover the workdir for this configuration.
Source code in vcs-versioning/src/vcs_versioning/_config.py
485 486 487 488 489 | |
from_data
classmethod
from_data(relative_to: str | PathLike[str], data: dict[str, Any], _env: VcsEnvironment | None = None) -> Configuration
given configuration data create a config instance after validating tag regex/version class
Source code in vcs-versioning/src/vcs_versioning/_config.py
545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 | |
from_file
classmethod
from_file(name: str | PathLike[str] = 'pyproject.toml', dist_name: str | None = None, pyproject_data: PyProjectData | None = None, *, tool_names: tuple[str, ...] | None = None, env: Mapping[str, str] | None = None, _env: VcsEnvironment | None = None, **kwargs: Any) -> Configuration
Read Configuration from pyproject.toml (or similar).
Raises exceptions when file is not found or toml is
not installed or the file has invalid format.
Parameters: - name: path to pyproject.toml - dist_name: name of the distribution - tool_names: env-var prefix order for TOML overrides - env: environment mapping for TOML overrides (default: os.environ) - _env: VcsEnvironment to attach to the resulting Configuration - **kwargs: additional keyword arguments to pass to the Configuration constructor
Source code in vcs-versioning/src/vcs_versioning/_config.py
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 | |