# How to Use Version Management in the Fabrica-Kit: Parsing and Validating Service Versions

> Learn how to manage service versions in Fabrica-Kit. Parse zone-prefixed strings like us-v1.20230428_153224 using the version package for reliable service identification.

- Repository: [Pantheon/fabrica-kit](https://github.com/go-pantheon/fabrica-kit)
- Tags: how-to-guide
- Published: 2026-03-02

---

**Fabrica-Kit centralizes version handling in the `version` package, where `GetSubVersion` parses zone-prefixed strings like `"us-v1.20230428_153224"` into availability zones and numeric components for reliable service identification.**

Fabrica-Kit provides a robust version management system through its dedicated `version` package and global profile state. This system allows services to parse, validate, and propagate standardized version strings across distributed deployments. According to the `go-pantheon/fabrica-kit` source code, version strings follow a strict `zone-v<major>.<minor>` pattern that enables precise service identification and compatibility checks.

## Understanding the Version String Format

Fabrica-Kit expects version strings to follow the exact pattern `zone-v<major>.<minor>`. This format encodes both geographic deployment information and semantic versioning data in a single identifier.

The parser enforces these rules:

- **Zone prefix**: Any non-empty identifier representing the availability zone or region (e.g., `"us"`, `"eu"`, `"asia"`)
- **Major version**: A decimal integer following the literal `"v"` character
- **Minor version**: A decimal integer that may contain underscores which are automatically stripped (e.g., `20230428_153224` becomes `20230428153224`)

Valid examples include `"us-v1.20230428_153224"` and `"eu-v2.0"`. Invalid strings that lack the `"v"` prefix, contain wrong section counts, or include extra components will fail validation.

## Parsing Versions with `GetSubVersion`

The `version` package exposes **`GetSubVersion`** in [`version/version.go`](https://github.com/go-pantheon/fabrica-kit/blob/main/version/version.go) as the primary mechanism for decomposing version strings into structured data.

### Function Signature and Return Values

Call `GetSubVersion` with a version string to receive three values:

```go
az, sv, ok := version.GetSubVersion(v)

```

- **`az`** (`string`): The availability-zone or region prefix (the part before the hyphen)
- **`sv`** (`[]int64`): A two-element slice containing the major and minor numbers as integers
- **`ok`** (`bool`): `true` only if the input matches the required `zone-vX.Y` pattern

When parsing `"us-v1.20230428_153224"`, the function returns `"us"` for the zone, `[]int64{1, 20230428153224}` for the versions, and `true` for success.

### Handling Invalid Versions

If the string does not conform to the expected pattern, `GetSubVersion` returns defensive empty values. The function provides `false` for the `ok` boolean, an empty string for `az`, and `nil` for `sv`. This design allows safe error handling without panic risks.

## Integrating Version Management with the Global Profile

During service startup, the **`profile.Init`** function stores the version string in global state accessible via **`profile.Version()`**. This integration lives in [`profile/vars.go`](https://github.com/go-pantheon/fabrica-kit/blob/main/profile/vars.go), where the package maintains a private `_version` variable and exposes it through the getter function.

Typical initialization looks like this:

```go
profile.Init("my-service", profile.ProfileProd, "blue", 2, "eu-v2.0", "node-42")

```

After initialization, `profile.Version()` returns `"eu-v2.0"`, which you can then pass to `version.GetSubVersion` for parsing. This pattern ensures version metadata propagates consistently across logging, metrics, and compatibility checks.

## Practical Implementation Examples

The `version` package includes comprehensive unit tests in [`version/version_test.go`](https://github.com/go-pantheon/fabrica-kit/blob/main/version/version_test.go) demonstrating expected behaviors. These examples show common production usage patterns.

### Parsing a Valid Version String

Extract zone and version components from a properly formatted service identifier:

```go
package main

import (
	"fmt"

	"github.com/go-pantheon/fabrica-kit/version"
)

func main() {
	v := "us-v1.20230428_153224"
	az, sv, ok := version.GetSubVersion(v)
	if !ok {
		fmt.Println("invalid version")
		return
	}
	fmt.Printf("zone: %s, major: %d, minor: %d\n", az, sv[0], sv[1])
	// Output: zone: us, major: 1, minor: 20230428153224
}

```

### Detecting Invalid Formats

Validate user input or configuration values before processing:

```go
az, sv, ok := version.GetSubVersion("invalid-format")
if !ok {
    // sv is nil and az is ""
    fmt.Println("Version string does not follow zone-vX.Y pattern")
}

```

### Accessing Version Data from the Global Profile

Combine profile initialization with version parsing for runtime service identification:

```go
package main

import (
	"github.com/go-pantheon/fabrica-kit/profile"
	"github.com/go-pantheon/fabrica-kit/version"
)

func initService() {
	// Example: service is started with version "eu-v2.0"
	profile.Init("my-service", profile.ProfileProd, "blue", 2, "eu-v2.0", "node-42")

	ver := profile.Version() // "eu-v2.0"
	az, sv, ok := version.GetSubVersion(ver)
	if ok {
		// Use az and sv for logging, metrics, or compatibility checks
		_ = az   // e.g., "eu"
		_ = sv[0] // major version 2
	}
}

```

## Summary

- **Fabrica-Kit version management** relies on the `version` package and `profile` integration for standardized service identification.
- **Strict format compliance** is required: version strings must follow `zone-v<major>.<minor>` where underscores in the minor version are ignored.
- **`GetSubVersion`** in [`version/version.go`](https://github.com/go-pantheon/fabrica-kit/blob/main/version/version.go) provides safe parsing with boolean validation to prevent runtime errors from malformed strings.
- **Global state management** occurs through `profile.Init` and `profile.Version()` in [`profile/vars.go`](https://github.com/go-pantheon/fabrica-kit/blob/main/profile/vars.go), making version data accessible throughout the service lifecycle.
- **Comprehensive testing** in [`version/version_test.go`](https://github.com/go-pantheon/fabrica-kit/blob/main/version/version_test.go) validates both valid patterns and edge cases for reliable production deployment.

## Frequently Asked Questions

### What format does Fabrica-Kit require for version strings?

Fabrica-Kit requires the format `zone-v<major>.<minor>`, where `zone` is a non-empty identifier, `major` is a decimal integer, and `minor` is a decimal integer that may contain underscores. The parser ignores underscores in the minor component, allowing timestamps like `20230428_153224` to be treated as `20230428153224`.

### How does `GetSubVersion` handle timestamps in version minors?

The function automatically strips underscores from the minor version component before converting it to an integer. This allows version strings like `"us-v1.20230428_153224"` to parse correctly, returning `20230428153224` as the minor version number without requiring pre-processing.

### Where is the service version stored after calling `profile.Init`?

The version string is stored in the private `_version` variable within [`profile/vars.go`](https://github.com/go-pantheon/fabrica-kit/blob/main/profile/vars.go). The package exposes this value through the `profile.Version()` getter function, making it accessible to any package that imports `github.com/go-pantheon/fabrica-kit/profile`.

### What happens when `GetSubVersion` receives an invalid version?

When the input string fails to match the `zone-vX.Y` pattern, `GetSubVersion` returns an empty string for the zone, `nil` for the version slice, and `false` for the boolean `ok` flag. This defensive return pattern allows callers to implement explicit error handling without risking nil pointer dereferences.