Skip to content
Back to skills

1605 Dynamic Version Overview D5360aa4

ASecurity

Guide to implementing dynamic versioning in Hatchling. Covers available sources (regex, code, env), choosing appropriate sources, version resolution at build time, and troubleshooting strategies.

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 11, 2026
developmentpythongobashnodenodejsexpressdebugginggitci/cdperformance

Works with

  • cli

Security analysis

A92/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro shows the line behind each finding and how to fix it

Scanned October 11, 2026

npx -y skills add tools-only/X-Skills --skill 1605-dynamic-version-overview_d5360aa4 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 1605 Dynamic Version Overview D5360aa4?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 1605 Dynamic Version Overview D5360aa4
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-1605-dynamic-version-overview-d5360aa4/badge)](https://www.skillsdirectory.com/skills/tools-only-1605-dynamic-version-overview-d5360aa4)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

SKILL.md
---
title: Dynamic Version Sources Overview
description: Guide to implementing dynamic versioning in Hatchling. Covers available sources (regex, code, env), choosing appropriate sources, version resolution at build time, and troubleshooting strategies.
---

# Dynamic Version Sources Overview

Dynamic versioning in Hatchling allows projects to determine versions at build time from external sources rather than hardcoding in `pyproject.toml`. This approach enables automated version management, integration with version control systems, and flexible deployment workflows.

## Configuration Basics

To use dynamic versioning, declare `version` as dynamic in your project metadata:

```toml
[project]
name = "my-package"
dynamic = ["version"]

[tool.hatch.version]
source = "regex"  # Version source plugin to use
# Additional configuration specific to the source
```

## Available Version Sources

Hatchling provides several built-in version source plugins:

| Source  | Description                               | Use Case                                     |
| ------- | ----------------------------------------- | -------------------------------------------- |
| `regex` | Extract version using regular expressions | Default; simple file-based versioning        |
| `code`  | Import and execute Python code            | Complex version logic or multiple sources    |
| `env`   | Read from environment variables           | CI/CD integration, containerized deployments |

Third-party sources are also available:

| Source   | Description                            | Installation                       |
| -------- | -------------------------------------- | ---------------------------------- |
| `vcs`    | Version from VCS tags (Git, Mercurial) | `pip install hatch-vcs`            |
| `nodejs` | Read from package.json                 | `pip install hatch-nodejs-version` |

## Version Source Plugin Interface

All version source plugins implement the `VersionSourceInterface`:

```python
class VersionSourceInterface:
    """Interface for version source plugins."""

    PLUGIN_NAME: str  # Unique identifier for the plugin
    root: Path        # Project root directory
    config: dict      # Configuration from pyproject.toml

    def get_version_data(self) -> dict:
        """
        Retrieve version information.

        Returns:
            dict: Must contain 'version' key with version string
        """
        pass

    def set_version(self, version: str) -> None:
        """
        Update the version in the source.

        Args:
            version: New version string to set
        """
        pass
```

## Choosing a Version Source

### Decision Tree

```text
Is your version in a Python file?
├─ Yes → Is it a simple string assignment?
│  ├─ Yes → Use `regex` source
│  └─ No → Use `code` source
└─ No → Is it in environment/CI?
   ├─ Yes → Use `env` source
   └─ No → Consider third-party sources (vcs, nodejs, etc.)
```

### Comparison Matrix

| Feature               | `regex` | `code` | `env`     |
| --------------------- | ------- | ------ | --------- |
| **Setup Complexity**  | Low     | Medium | Low       |
| **Performance**       | Fast    | Slower | Fast      |
| **Flexibility**       | Medium  | High   | Low       |
| **CI/CD Integration** | Good    | Good   | Excellent |
| **Version Bumping**   | Yes     | Yes    | External  |
| **Multiple Files**    | No      | Yes    | N/A       |
| **Custom Logic**      | No      | Yes    | No        |

## Common Configuration Patterns

### Single Version File

Most projects use a dedicated version file:

```toml
[tool.hatch.version]
source = "regex"
path = "src/my_package/__about__.py"
```

With `__about__.py`:

```python
__version__ = "1.2.3"
```

### Version from Package **init**

Store version in the main package module:

```toml
[tool.hatch.version]
source = "regex"
path = "src/my_package/__init__.py"
pattern = "__version__ = ['\"](?P<version>[^'\"]+)['\"]"
```

### Environment-Based Versioning

For containerized or CI/CD workflows:

```toml
[tool.hatch.version]
source = "env"
variable = "PROJECT_VERSION"
default = "0.0.0+unknown"
```

### Complex Version Logic

For versions derived from multiple sources:

```toml
[tool.hatch.version]
source = "code"
path = "version_helper.py"
expression = "get_version()"
```

## Version Data Structure

Version source plugins return a dictionary that must contain at minimum:

```python
{
    "version": "1.2.3"  # Required: The version string
}
```

Some sources may return additional metadata:

```python
{
    "version": "1.2.3",
    "raw_version": "v1.2.3",  # Original format
    "source_file": "/path/to/file",  # Where version was found
    "timestamp": "2024-01-01T00:00:00Z"  # When determined
}
```

## Integration with Build Process

### Build-Time Resolution

Dynamic versions are resolved during:

1. **Package Building**: When creating wheels or source distributions
2. **Editable Installs**: When installing in development mode
3. **Metadata Generation**: When tools request project metadata
4. **Version Commands**: When using `hatch version` CLI

### Caching Behavior

Hatchling caches resolved versions during a build session to ensure consistency:

```python
# Version is resolved once per build
building wheel...  # Resolves version
building sdist...  # Uses cached version
```

## Working with Dynamic Versions

### Displaying Current Version

```bash
$ hatch version
1.2.3
```

### Updating Dynamic Versions

The update capability depends on the source plugin:

```bash
# For sources that support setting (regex, code)
$ hatch version patch
Old: 1.2.3
New: 1.2.4

# For read-only sources (env)
$ hatch version patch
Error: The 'env' source does not support setting versions
```

## Fallback Strategies

### Default Values

Some sources support fallback values:

```toml
[tool.hatch.version]
source = "env"
variable = "VERSION"
default = "0.0.0+dev"  # Used if variable not set
```

### Error Handling

Configure behavior when version cannot be determined:

```toml
[tool.hatch.version]
source = "regex"
path = "src/version.py"
strict = false  # Don't fail if file missing (uses 0.0.0)
```

## Metadata Hooks

For advanced scenarios, use metadata hooks to modify version data:

```python
# hatch_build.py
from hatchling.metadata.plugin.interface import MetadataHookInterface

class CustomMetadataHook(MetadataHookInterface):
    def update(self, metadata):
        # Modify version after source resolution
        version = metadata.get("version", "0.0.0")
        metadata["version"] = f"{version}+custom"
```

## Performance Considerations

### Resolution Timing

- **Build Time**: Version resolved when package is built
- **Not at Import**: Version isn't resolved when package is imported
- **Development Mode**: Resolved once during editable install

### Optimization Tips

1. **Use regex over code** when possible (faster)
2. **Cache expensive operations** in code source
3. **Avoid network calls** in version resolution
4. **Keep version files small** for quick parsing

## Migration Guide

### From setuptools-scm

```toml
# Old: setuptools-scm
[build-system]
requires = ["setuptools>=45", "setuptools-scm[toml]>=6.2"]

[tool.setuptools_scm]

# New: hatch-vcs
[build-system]
requires = ["hatchling", "hatch-vcs"]

[tool.hatch.version]
source = "vcs"
```

### From Static to Dynamic

```toml
# Old: Static
[project]
version = "1.2.3"

# New: Dynamic
[project]
dynamic = ["version"]

[tool.hatch.version]
source = "regex"
path = "src/my_package/__about__.py"
```

## Troubleshooting

### Common Issues

| Issue                        | Cause                                       | Solution                                |
| ---------------------------- | ------------------------------------------- | --------------------------------------- |
| Version not found            | File doesn't exist or pattern doesn't match | Check path and pattern configuration    |
| Import errors                | Circular dependencies in code source        | Isolate version logic from main package |
| Environment variable not set | Missing in environment                      | Provide default value                   |
| Version mismatch             | Multiple version sources                    | Ensure single source of truth           |

### Debugging

Enable verbose output to debug version resolution:

```bash
$ hatch version -v
Looking for version in src/my_package/__about__.py
Pattern: __version__ = ["']([^"']+)["']
Found: 1.2.3
```

## Best Practices

1. **Single Source of Truth**: Define version in one place only
2. **Simple Patterns**: Use straightforward regex patterns
3. **Fast Resolution**: Avoid expensive operations during version resolution
4. **Clear Errors**: Provide helpful error messages when version not found
5. **Document Choice**: Explain version source selection in README
6. **Test Resolution**: Verify version resolution in CI/CD
7. **Provide Fallbacks**: Include default values for resilience

## See Also

- [Code Version Source](./code-version-source.md)
- [Regex Version Source](./regex-version-source.md)
- [Environment Version Source](./env-version-source.md)
- [Version Source Plugin Interface](./version-source-interface.md)
- [Creating Custom Version Sources](./custom-version-sources.md)

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.