# 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:

```toml title="pyproject.toml"
[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](usage.md#simplified-activation-new) 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 in `relative_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](extending.md#setuptools_scmversion_scheme) 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](extending.md#setuptools_scmlocal_scheme) 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`:

```toml title="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 --match` and is stripped before version
    parsing.

    Use this for monorepos or multi-package repositories where each package
    has its own tag namespace.

    ```toml title="pyproject.toml – monorepo example"
    [tool.setuptools_scm.tag]
    prefix = "hatchling-v"   # matches hatchling-v1.0.0, strips to 1.0.0
    ```

    | `tag.prefix` value | Tags matched | Extracted version |
    |--------------------|-------------|-------------------|
    | `""` (default)     | `v1.0.0`, `1.0.0`, `2026-event` | `v1.0.0`, `1.0.0` |
    | `"v"` | `v1.0.0`, `V1.0.0` | `1.0.0` |
    | `"hatchling-v"` | `hatchling-v1.0.0` | `1.0.0` |
    | `"py-v"` | `py-v2.3.1` | `2.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]*`). |
    | `true` | **Strict** – tags must contain at least one dot (e.g. `*[0-9]*.*[0-9]*`).  Event-like tags such as `2026-event` are rejected. |
    | `false` | **Permissive** – matches any tag containing a digit (`*[0-9]*`). |

    !!! note "Migration"

        In a future major release the default will change from permissive to strict.
        Set `tag.strict = false` now if you rely on the permissive matching, or
        `tag.strict = true` to adopt the stricter behavior early.

        While `tag.strict` is 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 with `SETUPTOOLS_SCM_DEBUG=ERROR`
        if you cannot act on it, for example when building someone else's
        project from a checkout.

    `tag.prefix` and `tag.strict` compose naturally:

    | `tag.prefix` | `tag.strict` | Effective `--match` glob |
    |---|---|---|
    | `""` | `false` / unset | `*[0-9]*` |
    | `""` | `true` | `*[0-9]*.*[0-9]*` |
    | `"hatchling-v"` | `false` / unset | `hatchling-v*[0-9]*` |
    | `"hatchling-v"` | `true` | `hatchling-v*[0-9]*.*[0-9]*` |

    !!! note "Mercurial"

        Mercurial applies the equivalent regex (`\d+` / `\d+\.\d+`, prefixed
        when `tag.prefix` is set) both when looking for the latest tag and when
        the checked-out changeset carries tags of its own.  Under
        `tag.strict = true` a changeset tagged only with event-style names is
        treated as untagged, so versioning continues from the last real version
        tag -- the same thing `git describe --match` does.

        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.prefix` has been stripped.  The regex needs a single capture group
    or a named group `version`.

    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.prefix` and `tag.strict` instead of
        customizing the regex directly.

`tag_regex` (deprecated)
:   **Deprecated**: Use `tag.regex` instead.

    Top-level `tag_regex` is still accepted for backward compatibility but
    emits a `DeprecationWarning`.  It cannot be used together with `tag.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 with `tag_regex` to 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 case `parentdir_prefix_version` can be set e.g. to `projectname-`).

`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-scm` will 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 `root` parameter is used; when it's not
    available, `fallback_root` is 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 to `False` is equivalent to setting
    `version_cls` to [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
    `str` should 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 while `setuptools-scm`
    is integrated in a setuptools packaging process, the non-normalized
    version number will appear in all files (see `version_file` note).

    !!! note "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 --long` command.

    Defaults to the value set by [vcs_versioning._backends._git.DEFAULT_DESCRIBE][]

    !!! warning "Overrides tag.strict"

        When `scm.git.describe_command` is explicitly set, it supplies its own
        `--match` pattern, so `tag.strict` has no effect on tag matching.  A
        warning is emitted only if the two would actually select different
        tags for your repository.

        `tag.prefix` is *not* overridden: it still strips the prefix from the
        selected tag before version parsing, so combining it with an explicit
        `describe_command` is 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 when `HEAD` is exactly on a tag, where a shallow clone is sufficient)
    - `"fail_on_shallow"`: Fails with an error when the repository is shallow (not when `HEAD` is exactly on a tag)
    - `"fetch_on_shallow"`: Automatically fetches to rectify shallow repositories (skipped when `HEAD` is exactly on a tag)
    - `"fail_on_missing_submodules"`: Fails when submodules are defined but not initialized

        The `"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_parse` parameter 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, as `git describe` does.
    - `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.

    ```toml
    [tool.setuptools_scm.scm.git]
    distance_scope = true
    ```

    Use 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:

    ```toml
    [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.

    !!! warning "set `tag.prefix` when projects are tagged separately"

        `git describe` picks the topologically nearest tag, which in a
        monorepo tagged `pkg-a-v1.2`, `pkg-b-v3.0` may 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.3` for everything) need no prefix.

    !!! warning "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 of `scm.git.pre_parse`.

    !!! note "git archives carry a repository-wide distance"

        `git archive` records 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 distance `0`
        and 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_scope` restricts them.
    Ignored when `distance_scope` is 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 `HEAD` but not from
    the tag, so neither can make the distance shrink as mainline history
    advances.  Git's own default history simplification (what plain
    `git log -- path` shows) 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_command` instead.

    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.py`` file within the
    package, typically used to avoid using `importlib.metadata`
    (which adds some overhead).

    !!! warning ""

        Only files with `.py` and `.txt` extensions have builtin templates,
        for other file types it is necessary to provide `version_file_template`.

`version_file_template: str | None = None`
:   A new-style format string taking `version`, `scm_version` and `version_tuple` as parameters.
    `version` is the generated next_version as string,
    `version_tuple` is a tuple of split numbers/strings and
    `scm_version` is the `ScmVersion` instance the current `version` was rendered from

`write_to_source: bool | None = None`
:   Controls whether version files (specified by `version_file` or `write_to`) are
    written to the source tree during version inference.

    | Value   | Behavior |
    |---------|----------|
    | unset   | Writes to source tree **and** emits a `DeprecationWarning` advising you to set this option explicitly, since the default will change in a future major release. |
    | `true`  | Writes to source tree, no warning — explicit opt-in. |
    | `false` | Does **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_SOURCE` environment variable overrides this setting
    (see [Environment Variables](#environment-variables) below).

    !!! note "Deprecation cycle"

        In a future major release, the default will change from writing to source to
        **not** writing to source. Set `write_to_source = true` now if you rely on
        version files being present in your source tree.

    ```toml title="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_file` instead.

## 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

    !!! warning ""

        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-scm``

    the 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](overrides.md#pretend-metadata-core) 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-date`` and ``node-and-timestamp`` local parts are
    derived, otherwise the current time is used.
    Standard environment variable from [reproducible-builds.org](https://reproducible-builds.org/docs/source-date-epoch/).

### setuptools-scm Overrides

These environment variables control setuptools-scm specific behavior.

`SETUPTOOLS_SCM_IGNORE_VCS_ROOTS`
:   A ``os.pathsep`` separated 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 ``chg`` to 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](overrides.md#config-overrides) for details.

`SETUPTOOLS_SCM_WRITE_TO_SOURCE`
:   Override the `write_to_source` configuration option. Set to `1`/`true`/`yes`
    to write version files to the source tree, or `0`/`false`/`no` to 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](overrides.md#subprocess-timeouts) 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 `jj` binary is not installed.
    Without this variable, a missing `jj` binary in a `.jj/` repository
    raises an error.

    Also available as `VCS_VERSIONING_DISABLE_JJ`.

    See [Jujutsu repositories](usage.md#jujutsu-jj-repositories) for details.

## Automatic File Inclusion

!!! warning "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:

1. Automatically discovers SCM-managed files (Git, Mercurial, Jujutsu)
2. Includes them in source distributions (`python -m build --sdist`)
3. Works for `include_package_data = True` in package building

**Entry point registration:**

```toml
[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:

```text title="MANIFEST.in"
# 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:**

```bash
# 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
```

!!! note "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
    options:
      heading_level: 4

::: vcs_versioning._backends._git.DEFAULT_DESCRIBE
    options:
      heading_level: 4


### the configuration class

::: vcs_versioning.Configuration
    options:
      heading_level: 4
