Skip to content
Back to skills

1607 Version Build Hook 36209f9b

ASecurity

Automatically write version information to files during build. Covers configuration, templating, target-specific hooks, and runtime version access patterns.

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 11, 2026
developmentpythongobashgitapici/cd

Works with

  • cli
  • api

Security analysis

A96/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 1607-version-build-hook_36209f9b --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 1607 Version Build Hook 36209f9b?

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

Security grade badge for 1607 Version Build Hook 36209f9b
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-1607-version-build-hook-36209f9b/badge)](https://www.skillsdirectory.com/skills/tools-only-1607-version-build-hook-36209f9b)

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

SKILL.md
---
title: Version Build Hook
description: Automatically write version information to files during build. Covers configuration, templating, target-specific hooks, and runtime version access patterns.
---

# Version Build Hook

The version build hook is a powerful feature that automatically writes version information to files during the build process. This ensures packaged code always contains the correct version, regardless of how it's determined (static, dynamic, or from environment variables).

## Overview

The version build hook:

- Runs during package building (wheel, sdist)
- Creates or updates files with version information
- Supports templating for custom formats
- Works with all version sources
- Ensures version availability at runtime

## Basic Configuration

Enable the version build hook in your `pyproject.toml`:

```toml
[tool.hatch.build.hooks.version]
path = "src/my_package/_version.py"
```

This creates `_version.py` during build:

```python
# Automatically generated by Hatch
__version__ = "1.2.3"
```

## Configuration Options

### Global Hook Configuration

```toml
[tool.hatch.build.hooks.version]
path = "src/my_package/_version.py"
template = '__version__ = "{version}"'
pattern = "__version__ = ['\"](?P<version>[^'\"]+)['\"]"
```

### Target-Specific Configuration

Configure per build target:

```toml
# For wheels only
[tool.hatch.build.targets.wheel.hooks.version]
path = "src/my_package/_version.py"

# For source distributions only
[tool.hatch.build.targets.sdist.hooks.version]
path = "src/my_package/_version.py"
```

### Configuration Parameters

| Parameter  | Type        | Description                        | Default                     |
| ---------- | ----------- | ---------------------------------- | --------------------------- |
| `path`     | string      | File path to write version         | Required                    |
| `template` | string      | Template for file content          | `__version__ = "{version}"` |
| `pattern`  | string/bool | Pattern for updating existing file | `true` (uses default)       |

## Template Formatting

### Simple Template

Basic version string:

```toml
[tool.hatch.build.hooks.version]
path = "src/my_package/_version.py"
template = '__version__ = "{version}"'
```

Result:

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

### Multi-line Template

Include additional metadata:

```toml
[tool.hatch.build.hooks.version]
path = "src/my_package/_version.py"
template = '''
"""Version information."""
__version__ = "{version}"
__version_tuple__ = {version_tuple}
'''
```

Result:

```python
"""Version information."""
__version__ = "1.2.3"
__version_tuple__ = (1, 2, 3)
```

### Available Template Variables

| Variable          | Description         | Example     |
| ----------------- | ------------------- | ----------- |
| `{version}`       | Full version string | `"1.2.3"`   |
| `{version_tuple}` | Version as tuple    | `(1, 2, 3)` |

### Custom Templates

Complex version information:

```toml
[tool.hatch.build.hooks.version]
path = "src/my_package/version_info.py"
template = '''
"""
Automatically generated version information.
Do not edit this file manually.
"""

from typing import Tuple

__version__: str = "{version}"
__version_tuple__: Tuple[int, ...] = {version_tuple}

def get_version() -> str:
    """Get the current version."""
    return __version__

def get_version_tuple() -> Tuple[int, ...]:
    """Get version as a tuple of integers."""
    return __version_tuple__
'''
```

## Pattern-Based Updates

### Using Default Pattern

The default pattern matches standard Python version declarations:

```toml
[tool.hatch.build.hooks.version]
path = "src/my_package/__init__.py"
pattern = true  # Use default pattern
```

Updates existing version in file:

```python
# Before build
__version__ = "0.0.0"  # Placeholder

# After build
__version__ = "1.2.3"  # Updated
```

### Custom Pattern

Specify custom regex patterns:

```toml
[tool.hatch.build.hooks.version]
path = "setup.cfg"
template = "version = {version}"
pattern = "version = .*"
```

Updates:

```ini
# Before
[metadata]
version = 0.0.0

# After
[metadata]
version = 1.2.3
```

### JSON File Updates

Update version in JSON files:

```toml
[tool.hatch.build.hooks.version]
path = "package.json"
template = '  "version": "{version}",'
pattern = '  "version": "[^"]*",'
```

## Integration Patterns

### With Dynamic Version Sources

Works seamlessly with all version sources:

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

[tool.hatch.version]
source = "regex"
path = "VERSION"

[tool.hatch.build.hooks.version]
path = "src/my_package/_version.py"
```

Build process:

1. Read version from `VERSION` file
2. Write version to `_version.py`
3. Include both in package

### With Environment Variables

Perfect for CI/CD:

```toml
[tool.hatch.version]
source = "env"
variable = "BUILD_VERSION"

[tool.hatch.build.hooks.version]
path = "src/my_package/_version.py"
```

```bash
BUILD_VERSION=1.2.3 hatch build
# Creates _version.py with version 1.2.3
```

### Multiple Version Files

Create multiple version files:

```toml
# Primary version file
[tool.hatch.build.hooks.version]
path = "src/my_package/_version.py"

# Additional version files via custom hook
[tool.hatch.build.hooks.custom]
path = "hatch_build.py"
```

```python
# hatch_build.py
from pathlib import Path

def initialize(version, build_config):
    """Create additional version files."""

    # Create version.txt
    version_txt = Path("src/my_package/version.txt")
    version_txt.write_text(version)

    # Create VERSION file
    version_file = Path("VERSION")
    version_file.write_text(version)
```

## Runtime Version Access

### Method 1: Import Version File

```python
# src/my_package/__init__.py
try:
    from ._version import __version__
except ImportError:
    __version__ = "unknown"
```

### Method 2: With Fallback

```python
# src/my_package/__init__.py
try:
    from ._version import __version__
except ImportError:
    # Development mode - version file not created yet
    try:
        from importlib import metadata
        __version__ = metadata.version("my-package")
    except Exception:
        __version__ = "0.0.0+dev"
```

### Method 3: Version Module

```python
# src/my_package/version.py (created by hook)
__version__ = "1.2.3"

# src/my_package/__init__.py
from .version import __version__
```

## Build Target Specific Hooks

### Different Files for Different Targets

```toml
# Wheel gets compiled version
[tool.hatch.build.targets.wheel.hooks.version]
path = "src/my_package/_version.py"
template = '__version__ = "{version}"'

# Source distribution gets detailed version
[tool.hatch.build.targets.sdist.hooks.version]
path = "src/my_package/_version_full.py"
template = '''
__version__ = "{version}"
__version_tuple__ = {version_tuple}
__build_date__ = "2024-01-01"
'''
```

### Conditional Hook Activation

```toml
# Only for wheel builds
[tool.hatch.build.targets.wheel]
hooks = ["version"]

# No version hook for sdist
[tool.hatch.build.targets.sdist]
hooks = []  # Explicitly no hooks
```

## Advanced Usage

### Dynamic Path

Use context formatting for paths:

```toml
[tool.hatch.build.hooks.version]
path = "src/{name}/_version.py"  # Uses project name
```

### Version File in Multiple Locations

For monorepos or complex projects:

```python
# hatch_build.py
from pathlib import Path

def initialize(version, build_config):
    """Write version to multiple locations."""

    locations = [
        "packages/core/version.py",
        "packages/cli/version.py",
        "packages/api/version.py",
    ]

    template = f'__version__ = "{version}"'

    for location in locations:
        path = Path(location)
        path.parent.mkdir(parents=True, exist_ok=True)
        path.write_text(template)
```

### Version with Build Metadata

Include build information:

```python
# hatch_build.py
import os
from datetime import datetime
from pathlib import Path

def initialize(version, build_config):
    """Create version file with build metadata."""

    build_info = {
        "version": version,
        "build_date": datetime.now().isoformat(),
        "build_host": os.environ.get("HOSTNAME", "unknown"),
        "build_user": os.environ.get("USER", "unknown"),
        "ci_build": os.environ.get("CI", "false"),
    }

    template = f"""
# Automatically generated build information
__version__ = "{build_info['version']}"
__build_date__ = "{build_info['build_date']}"
__build_host__ = "{build_info['build_host']}"
__build_user__ = "{build_info['build_user']}"
__ci_build__ = {build_info['ci_build']}
"""

    version_file = Path("src/my_package/_build_info.py")
    version_file.write_text(template)
```

## Development Workflow

### Editable Installs

Version files are NOT created during editable installs:

```bash
# Editable install
$ pip install -e .
# No _version.py created

# Regular install
$ pip install .
# _version.py is created
```

Handle this in your code:

```python
try:
    from ._version import __version__
except ImportError:
    # In development mode
    __version__ = "0.0.0+dev"
```

### Git Ignore

Add generated version files to `.gitignore`:

```gitignore
# Generated version files
src/my_package/_version.py
*/_version.py
*/_build_info.py
```

### Pre-commit Hook

Ensure version files aren't committed:

```yaml
# .pre-commit-config.yaml
repos:
  - repo: local
    hooks:
      - id: check-version-file
        name: Check version file not committed
        entry: sh -c 'test ! -f src/my_package/_version.py'
        language: system
        files: _version\.py$
        pass_filenames: false
```

## Troubleshooting

### File Not Created

Issue: Version file missing after build

Check:

1. Hook is enabled in configuration
2. Path is correct and parent directories exist
3. No errors during build process

```bash
# Debug build
$ hatch build -v
# Look for version hook execution
```

### Template Syntax Error

Issue: Invalid template format

```toml
# Wrong - missing quotes
template = __version__ = {version}

# Correct
template = '__version__ = "{version}"'
```

### Pattern Not Matching

Issue: Existing file not updated

Debug pattern:

```python
import re
pattern = r"__version__ = ['\"](?P<version>[^'\"]+)['\"]"
content = open("src/my_package/__init__.py").read()
match = re.search(pattern, content)
print(f"Match: {match.group('version') if match else 'No match'}")
```

### Version Import Error

Issue: Can't import version at runtime

Solutions:

1. Ensure version file is included in package
2. Check import path is correct
3. Add try/except for development mode

## Best Practices

### 1. Use Dedicated Version Files

Keep version separate from other code:

```toml
# Good
path = "src/my_package/_version.py"

# Less ideal
path = "src/my_package/__init__.py"  # Mixed with other code
```

### 2. Include Fallbacks

Always handle missing version files:

```python
try:
    from ._version import __version__
except ImportError:
    __version__ = "unknown"
```

### 3. Document Generated Files

Add header to templates:

```toml
template = '''
# This file is automatically generated by the build process.
# Do not edit manually.
__version__ = "{version}"
'''
```

### 4. Test Version Access

Add tests for version availability:

```python
def test_version():
    """Test that version is accessible."""
    import my_package
    assert hasattr(my_package, "__version__")
    assert my_package.__version__ != "unknown"
```

## See Also

- [Dynamic Version Sources](./dynamic-version-overview.md)
- [Build Configuration](./build-configuration.md)
- [Custom Build Hooks](./custom-build-hooks.md)
- [Version CLI Commands](./version-cli.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.