Go SDK
SDK to integrate Phase in server-side applications running Go.
Prerequisites
- Have signed up for the Phase Console and created an App
- Get a
PHASE_SERVICE_TOKEN
Starting from version 2.0.0, the Phase Go SDK is a pure Go implementation and no longer requires libsodium or CGO.
Upgrading from v1.x: Update your module dependency and imports from github.com/phasehq/golang-sdk to github.com/phasehq/golang-sdk/v2:
go get github.com/phasehq/golang-sdk/v2/phase
Then update your imports:
// 1.x.x
import "github.com/phasehq/golang-sdk/phase"
// 2.x.x
import "github.com/phasehq/golang-sdk/v2/phase"
Users on v1.x are unaffected and can continue using github.com/phasehq/golang-sdk without changes.
Install the SDK
Install the SDK using go get.
Install
go get github.com/phasehq/golang-sdk/v2/phase
Import the SDK
Import the SDK in your Go files to start using its features.
import "github.com/phasehq/golang-sdk/v2/phase"
Initialize the SDK
Before interacting with the Phase service, initialize the SDK with your service token and the host information.
Parameters:
tokentypestring: Your Phase Service Token (pss_service:v1:...orpss_service:v2:...) or User Token (pss_user:v1:...)hosttypestring: The URL of the Phase Console instance. Defaults tohttps://console.phase.devif empty.debugtypebool: Setting to true will result in a higher level of log verbosity useful when debugging
package main
import (
"log"
"github.com/phasehq/golang-sdk/v2/phase"
)
func main() {
token := "pss_service:v1:....."
host := "https://console.phase.dev" // Adjust this for a self-hosted instance of Phase
debug := false // For logging verbosity, disable in production
p, err := phase.New(token, host, debug)
if err != nil {
log.Fatalf("Failed to initialize Phase client: %v", err)
}
}
Usage
All operations accept either AppID or AppName to identify your application. AppID is recommended as it avoids ambiguity when multiple applications share the same name.
You can get the AppID by going to your application settings in the Phase Console, hovering over UUID under the App section and clicking the Copy button:

Secret Types
Phase supports three secret types, available as constants:
| Constant | Value | Description |
|---|---|---|
phase.SecretTypeSecret | "secret" | Default — standard encrypted secret |
phase.SecretTypeSealed | "sealed" | Write-only — value cannot be read back after creation |
phase.SecretTypeConfig | "config" | Non-sensitive configuration value |
Use phase.ValidateSecretType(t) to validate a type string — returns nil for valid types (including empty string, which defaults to "secret").
Creating Secrets
Define key-value pairs and specify the Environment, App name or ID, and path (optional) to create new Secrets.
Options:
type CreateOptions struct {
KeyValuePairs []phase.KeyValuePair
EnvName string
AppID string
AppName string // Alternative to AppID
Path string
OverrideValue string
Type string // "secret" (default), "sealed", or "config" — applied to all pairs when KeyValuePair.Type is empty
}
type KeyValuePair struct {
Key string
Value string
Type string // Per-pair type override; takes precedence over CreateOptions.Type
}
err := p.Create(phase.CreateOptions{
KeyValuePairs: []phase.KeyValuePair{
{Key: "API_KEY", Value: "api_secret"},
{Key: "DB_HOST", Value: "localhost:5432"},
},
EnvName: "Production",
AppID: "app-id-here", // Or use AppName: "MyApp"
Path: "/api/keys", // Optional, default path: /
})
if err != nil {
log.Fatalf("Failed to create secret: %v", err)
}
// Create a sealed secret (write-only)
err = p.Create(phase.CreateOptions{
KeyValuePairs: []phase.KeyValuePair{
{Key: "STRIPE_KEY", Value: "sk_live_..."},
},
EnvName: "Production",
AppID: "app-id-here",
Type: phase.SecretTypeSealed,
})
// Create config values (non-sensitive)
err = p.Create(phase.CreateOptions{
KeyValuePairs: []phase.KeyValuePair{
{Key: "APP_PORT", Value: "8080"},
{Key: "LOG_LEVEL", Value: "info"},
},
EnvName: "Production",
AppID: "app-id-here",
Type: phase.SecretTypeConfig,
})
Getting Secrets
Provide the Environment name, App name or ID, and optionally filter by specific keys, tags, and path.
Options:
type GetOptions struct {
EnvName string
AppID string
AppName string // Alternative to AppID
Keys []string // Optional: filter by specific key names
Tag string // Optional: filter by tag
Path string // Optional: filter by path (default: /)
Dynamic bool // Optional: include dynamic secrets
Lease bool // Optional: generate leases for dynamic secrets
LeaseTTL *int // Optional: lease TTL in seconds
Raw bool // Optional: skip ${REF} reference resolution
}
Each secret is returned as a SecretResult:
type SecretResult struct {
Key string
Value string
Comment string
Path string
Type string // "secret", "sealed", or "config"
Application string
Environment string
Tags []string
Overridden bool // true if a personal override is active
IsDynamic bool // true for dynamic secrets
DynamicGroup string // provider group label for dynamic secrets
}
Get all secrets
secrets, err := p.Get(phase.GetOptions{
EnvName: "Production",
AppID: "app-id-here", // Or use AppName: "MyApp"
})
if err != nil {
log.Fatalf("Failed to get secrets: %v", err)
}
for _, s := range secrets {
log.Printf("%s=%s", s.Key, s.Value)
}
Get specific keys
secrets, err := p.Get(phase.GetOptions{
EnvName: "Production",
AppID: "app-id-here",
Keys: []string{"API_KEY", "DB_HOST"},
})
Filter by tag and path
secrets, err := p.Get(phase.GetOptions{
EnvName: "Production",
AppID: "app-id-here",
Tag: "backend",
Path: "/api/config",
})
Include dynamic secrets with leases
secrets, err := p.Get(phase.GetOptions{
EnvName: "Production",
AppID: "app-id-here",
Dynamic: true,
Lease: true,
})
Updating a Secret
Provide the new value along with the environment name, application name or ID, and key to update an existing secret.
Options:
type UpdateOptions struct {
EnvName string
AppID string
AppName string // Alternative to AppID
Key string
Value string
SourcePath string // Path where the secret currently lives
DestinationPath string // Optional: move the secret to a new path
Override bool // Set a personal override
ToggleOverride bool // Toggle personal override on/off
Type string // "secret", "sealed", or "config" — leave empty to keep existing type
}
result, err := p.Update(phase.UpdateOptions{
EnvName: "Production",
AppID: "app-id-here", // Or use AppName: "MyApp"
Key: "API_KEY",
Value: "my_updated_api_secret",
})
if err != nil {
log.Fatalf("Failed to update secret: %v", err)
}
Deleting Secrets
Specify the environment name, application name or ID, keys to delete, and optionally the path.
Options:
type DeleteOptions struct {
EnvName string
AppID string
AppName string // Alternative to AppID
KeysToDelete []string
Path string
}
keysNotFound, err := p.Delete(phase.DeleteOptions{
EnvName: "Production",
AppID: "app-id-here", // Or use AppName: "MyApp"
KeysToDelete: []string{"API_KEY", "OLD_SECRET"},
Path: "/api/keys", // Optional, default path: /
})
if err != nil {
log.Fatalf("Failed to delete secret: %v", err)
}
if len(keysNotFound) > 0 {
log.Printf("Keys not found: %v", keysNotFound)
}
Get raw values without resolving references
secrets, err := p.Get(phase.GetOptions{
EnvName: "Production",
AppID: "app-id-here",
Raw: true, // ${REF} syntax is preserved as-is
})
Secret References
Get() automatically resolves ${REF} syntax in secret values before returning results. This includes same-environment (${KEY}), cross-environment (${staging.SECRET_KEY}), cross-app (${backend_api::production.API_KEY}), and path-scoped (${/backend/config/DB_HOST}) references.
// References are resolved automatically — no extra steps needed
secrets, _ := p.Get(phase.GetOptions{
EnvName: "Production",
AppID: "app-id-here",
})
for _, s := range secrets {
// s.Value already has all ${REF} references resolved
fmt.Printf("%s=%s\n", s.Key, s.Value)
}
To get raw, unresolved values (e.g. for display or inspection), set Raw: true:
secrets, _ := p.Get(phase.GetOptions{
EnvName: "Production",
AppID: "app-id-here",
Raw: true,
})
for _, s := range secrets {
// s.Value contains the original ${REF} syntax, not the resolved value
fmt.Printf("%s=%s\n", s.Key, s.Value)
}
Overrides
Create or update a personal override for a secret:
// Create a secret with an override value
err := p.Create(phase.CreateOptions{
KeyValuePairs: []phase.KeyValuePair{
{Key: "API_URL", Value: "https://api.example.com"},
},
EnvName: "Development",
AppID: "app-id-here",
OverrideValue: "http://localhost:3000",
})
// Update override for existing secret
_, err := p.Update(phase.UpdateOptions{
EnvName: "Development",
AppID: "app-id-here",
Key: "API_URL",
Value: "http://localhost:4000",
Override: true,
})
// Toggle override on/off
_, err := p.Update(phase.UpdateOptions{
EnvName: "Development",
AppID: "app-id-here",
Key: "API_URL",
ToggleOverride: true,
})