A blazingly fast Kubernetes package manager with Jinja2 templating
A modern Helm alternative written in Rust, featuring familiar Jinja2 templating syntax
Features • Installation • Quick Start • Commands • Templating
| Feature | Sherpack | Helm |
|---|---|---|
| Templating | Jinja2 (familiar syntax) | Go templates (complex) |
| Performance | Native Rust binary | Go runtime |
| Binary Size | ~19 MB | ~50 MB |
| Learning Curve | Minimal (if you know Jinja2) | Steep |
| Dependencies | None | None |
| Schema Validation | Built-in JSON Schema | External tools |
| Error Messages | Contextual suggestions | Generic errors |
| Helm Migration | Automatic chart converter | N/A |
| CRD Handling | Smart updates with safety analysis | Never updates CRDs |
| CRD Templating | Supported in crds/ and templates/ | Only in templates/ (dangerous) |
| Subchart Rendering | Full support with global values | Full support |
- Jinja2 Templating - Familiar Python-like syntax with
{{ }}and{% %} - Helm-Compatible Filters -
toyaml,tojson,b64encode,indent,nindent,quote, and 20+ more - Rich Function Library -
get(),ternary(),now(),uuidv4(),tostring(),fail() - Strict Mode - Catch undefined variables before deployment
- JSON Schema Support - Validate values against schema before rendering
- Default Extraction - Automatic default values from schema
- Helpful Error Messages - Contextual suggestions for typos and missing keys
- Archive Format - Reproducible tar.gz with SHA256 manifest
- Cryptographic Signatures - Minisign-based signing for supply chain security
- Integrity Verification - Verify archives before deployment
- Full Lifecycle Management - Install, upgrade, rollback, uninstall
- Server-Side Apply - Modern Kubernetes apply with conflict detection
- Hook Support - Pre/post install, upgrade, rollback, delete hooks
- Health Checks - Wait for deployments, custom HTTP/command probes
- Release Storage - Secrets, ConfigMap, or file-based storage
- Diff Preview - See changes before applying
- Smart CRD Updates - Safe updates with change analysis (24 change types)
- Intent-Based Policies - Explicit control via annotations (
managed,shared,external) - Templated CRDs - Support templating in both
crds/andtemplates/ - Deletion Protection - Impact analysis before CRD deletion
- Auto-Detection - CRDs in templates/ are automatically protected
- Rich Diff Output - See exactly what will change in CRD updates
- Full Subchart Rendering - Render subcharts with their own values
- Global Values - Pass global values to all subcharts
- Conditional Subcharts - Enable/disable via conditions and tags
- Files Object - Access files in subcharts (
.Files.Get,.Files.Glob)
- Automatic Conversion - Convert Helm charts to Sherpack packs
- Template Translation - Go templates → Jinja2 syntax
- Helper Function Support - Converts
include,define,range,with, etc. - Full Chart Compatibility - Tested with ingress-nginx (43 templates)
- Repository Management - HTTP, OCI, and file-based repositories
- Dependency Resolution - Lock file with version policies
- SQLite Search - Fast local search with FTS5
- OCI Registry Support - Push/pull to container registries
# Clone the repository
git clone https://github.com/alegeay/sherpack.git
cd sherpack
# Build release binary
cargo build --release
# Install to your PATH
cp target/release/sherpack ~/.local/bin/- Rust 1.85+ (Edition 2024)
- For Kubernetes operations:
kubectlconfigured with cluster access
sherpack create myappThis generates:
myapp/
├── Pack.yaml # Pack metadata
├── values.yaml # Default values
├── values.schema.yaml # Optional: JSON Schema
└── templates/
└── deployment.yaml # Kubernetes template
# values.yaml
app:
name: mywebapp
replicas: 3
image:
repository: nginx
tag: "1.25"
resources:
limits:
cpu: "500m"
memory: "256Mi"# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ release.name }}
namespace: {{ release.namespace }}
spec:
replicas: {{ values.app.replicas }}
template:
spec:
containers:
- name: {{ values.app.name | kebabcase }}
image: {{ values.image.repository }}:{{ values.image.tag }}
resources:
{{ values.resources | toyaml | nindent(12) }}# Validate against schema
sherpack validate ./myapp
# Lint the pack structure
sherpack lint ./myapp
# Render templates locally
sherpack template myrelease ./myapp
# Render with overrides
sherpack template myrelease ./myapp --set app.replicas=5 -n production# Install to cluster
sherpack install myrelease ./myapp -n production
# Upgrade existing release
sherpack upgrade myrelease ./myapp --set app.replicas=5
# View release status
sherpack status myrelease
# Rollback if needed
sherpack rollback myrelease 1
# Uninstall
sherpack uninstall myrelease| Command | Description |
|---|---|
sherpack template <name> <pack> |
Render templates to stdout |
sherpack lint <pack> |
Validate pack structure and templates |
sherpack validate <pack> |
Validate values against schema |
sherpack show <pack> |
Display pack information |
sherpack create <name> |
Scaffold a new pack |
sherpack convert <chart> |
Convert Helm chart to Sherpack pack |
| Command | Description |
|---|---|
sherpack package <pack> |
Create archive from pack directory |
sherpack inspect <archive> |
Show archive contents and manifest |
sherpack keygen |
Generate signing keypair |
sherpack sign <archive> |
Sign archive with private key |
sherpack verify <archive> |
Verify archive integrity and signature |
| Command | Description |
|---|---|
sherpack install <name> <pack> |
Install pack to cluster |
sherpack upgrade <name> <pack> |
Upgrade existing release |
sherpack uninstall <name> |
Remove release from cluster |
sherpack rollback <name> <rev> |
Rollback to previous revision |
sherpack list |
List installed releases |
sherpack history <name> |
Show release history |
sherpack status <name> |
Show release status |
sherpack recover <name> |
Recover stale release |
| Command | Description |
|---|---|
sherpack repo add <name> <url> |
Add repository |
sherpack repo list |
List repositories |
sherpack repo update [name] |
Update repository index |
sherpack repo remove <name> |
Remove repository |
sherpack search <query> |
Search for packs |
sherpack pull <pack> |
Download pack from repository |
sherpack push <archive> <dest> |
Push to OCI registry |
| Command | Description |
|---|---|
sherpack dependency list <pack> |
List pack dependencies |
sherpack dependency update <pack> |
Resolve and lock dependencies |
sherpack dependency build <pack> |
Download locked dependencies |
sherpack dependency tree <pack> |
Show dependency tree |
| Variable | Description | Example |
|---|---|---|
values.* |
Values from values.yaml | {{ values.app.name }} |
release.name |
Release name | {{ release.name }} |
release.namespace |
Target namespace | {{ release.namespace }} |
pack.name |
Pack name from Pack.yaml | {{ pack.name }} |
pack.version |
Pack version | {{ pack.version }} |
capabilities.* |
Cluster capabilities | {{ capabilities.kubeVersion }} |
| Filter | Description |
|---|---|
toyaml |
Object to YAML string |
tojson |
Object to compact JSON |
tojson_pretty |
Object to formatted JSON |
| Filter | Description |
|---|---|
b64encode |
Base64 encode |
b64decode |
Base64 decode |
sha256 |
SHA256 hash |
| Filter | Description |
|---|---|
quote / squote |
Wrap in quotes |
upper / lower |
Change case |
snakecase / kebabcase / camelcase |
Case conversion |
trunc(n) |
Truncate to n characters |
trimprefix(s) / trimsuffix(s) |
Remove prefix/suffix |
replace(old, new) |
Replace substring |
| Filter | Description |
|---|---|
indent(n) |
Add n spaces to each line |
nindent(n) |
Newline + indent |
| Filter | Description |
|---|---|
keys |
Get object keys |
haskey(k) |
Check if key exists |
merge(obj) |
Merge objects |
dictsort |
Sort for iteration |
first / last |
First/last element |
default(val) |
Default if undefined |
| Filter | Description |
|---|---|
required |
Fail if undefined/empty |
empty |
Check if empty |
| Filter | Description |
|---|---|
int |
Convert to integer |
float |
Convert to float |
string |
Convert to string |
| Function | Description |
|---|---|
get(obj, key, default) |
Safe access with default |
ternary(true, false, cond) |
Conditional value |
tostring(v) / toint(v) / tofloat(v) |
Type conversion |
now() |
Current ISO timestamp |
uuidv4() |
Random UUID |
fail(msg) |
Fail with message |
mypack/
├── Pack.yaml # Required: Pack metadata
├── values.yaml # Required: Default values
├── values.schema.yaml # Optional: JSON Schema for validation
├── Pack.lock.yaml # Generated: Locked dependencies
├── packs/ # Downloaded dependencies
└── templates/ # Required: Template files
├── deployment.yaml
├── service.yaml
└── _helpers.tpl # Optional: Shared helpers
apiVersion: sherpack/v1
kind: application
metadata:
name: myapp
version: 1.0.0
description: My application
appVersion: "2.0.0"
# Optional: Dependencies
dependencies:
- name: redis
version: ">=7.0.0"
repository: https://charts.example.com
# Optional: Engine settings
engine:
strict: true # Fail on undefined variables$schema: http://json-schema.org/draft-07/schema#
type: object
properties:
app:
type: object
properties:
name:
type: string
default: myapp
replicas:
type: integer
minimum: 1
maximum: 10
default: 3
required: [name]Sherpack supports lifecycle hooks for custom actions:
# templates/pre-install-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: {{ release.name }}-pre-install
annotations:
sherpack.io/hook: pre-install
sherpack.io/hook-weight: "0"
sherpack.io/hook-delete-policy: hook-succeeded
spec:
template:
spec:
containers:
- name: migrate
image: myapp:{{ values.image.tag }}
command: ["./migrate.sh"]
restartPolicy: Never| Phase | When |
|---|---|
pre-install |
Before install |
post-install |
After install |
pre-upgrade |
Before upgrade |
post-upgrade |
After upgrade |
pre-rollback |
Before rollback |
post-rollback |
After rollback |
pre-delete |
Before uninstall |
post-delete |
After uninstall |
test |
On sherpack test |
Sherpack provides superior CRD handling compared to Helm:
Use annotations to declare how CRDs should be managed:
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: myresources.example.com
annotations:
sherpack.io/crd-policy: managed # or: shared, external| Policy | Behavior | Use Case |
|---|---|---|
managed |
Owned by release, protected on uninstall | Operator CRDs |
shared |
Never deleted, even with --delete-crds |
Shared infrastructure |
external |
Don't touch (managed by GitOps) | External management |
Unlike Helm, Sherpack allows templating in crds/ directory:
# crds/myresource-crd.yaml
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: {{ values.crdName }}.{{ values.group }}
labels:
{{- values.labels | toyaml | nindent 4 }}CRD changes are analyzed by severity:
$ sherpack upgrade myrelease ./mypack --show-crd-diff
CRD Analysis: myresources.example.com
══════════════════════════════════════════════════════════════════
Versions:
✓ + Added API version v1beta2
Schema Changes:
✓ + Added optional field: spec.newFeature
⚠ ~ Tightened validation: spec.config.maxLength 256 → 128
✗ - Removed field: spec.deprecated (DANGEROUS)
Summary:
✓ 2 safe change(s)
⚠ 1 warning(s)
✗ 1 dangerous (require --force-crd-update)$ sherpack uninstall my-operator --delete-crds
⚠ CRD Deletion Impact Analysis
myresources.example.com:
Policy: managed
Existing resources: 47 across 12 namespaces
- production (23 resources)
- staging (15 resources)
This will PERMANENTLY DELETE all 47 resources.
Use --confirm-crd-deletion to proceed.Sherpack can automatically convert Helm charts to Sherpack packs:
# Convert a Helm chart
sherpack convert ./my-helm-chart
# Specify output directory
sherpack convert ./my-helm-chart -o ./my-sherpack-pack
# Preview without writing
sherpack convert ./my-helm-chart --dry-run
# Force overwrite existing
sherpack convert ./my-helm-chart --forceGo templates are automatically translated to Jinja2:
| Go Template | Jinja2 |
|---|---|
{{ .Values.name }} |
{{ values.name }} |
{{ include "helper" . }} |
{{ helper() }} |
{{- if .Values.enabled }} |
{% if values.enabled %} |
{{ range .Values.items }} |
{% for item in values.items %} |
{{ .Release.Name }} |
{{ release.name }} |
{{ default "foo" .Values.x }} |
{{ values.x | default("foo") }} |
{{ .Values.x | quote }} |
{{ values.x | quote }} |
{{ toYaml .Values | nindent 2 }} |
{{ values | toyaml | nindent(2) }} |
{{- define "name" }}→{% macro name() %}{{ include "name" . }}→{{ name() }}{{ if }}/{{ else }}/{{ end }}→{% if %}/{% else %}/{% endif %}{{ range }}/{{ end }}→{% for %}/{% endfor %}{{ with }}/{{ end }}→{% with %}/{% endwith %}or inline- Variable declarations:
$var := value - All common Helm functions and pipelines
# HTTP repository
sherpack repo add stable https://charts.example.com
# With authentication
sherpack repo add private https://charts.example.com --username user --password pass
# OCI registry
sherpack repo add oci oci://registry.example.com/charts# Search across repositories
sherpack search nginx
# Pull specific version
sherpack pull stable/nginx:1.0.0
# Pull from OCI
sherpack pull oci://registry.example.com/charts/nginx:1.0.0# Package and push
sherpack package ./myapp
sherpack push myapp-1.0.0.tar.gz oci://registry.example.com/charts/myapp:1.0.0sherpack/
├── crates/
│ ├── sherpack-core/ # Core types: Pack, Values, Context, Archive
│ ├── sherpack-engine/ # Template engine, filters, functions
│ ├── sherpack-convert/ # Helm chart to Sherpack converter
│ ├── sherpack-kube/ # Kubernetes client, storage, hooks, health
│ ├── sherpack-repo/ # Repository, OCI, dependencies, search
│ └── sherpack-cli/ # CLI commands
├── fixtures/
│ ├── simple-pack/ # Basic test fixture
│ ├── demo-pack/ # Comprehensive demo
│ └── helm-nginx/ # Helm conversion test
└── docs/ # Documentation
| Crate | Purpose | Tests |
|---|---|---|
sherpack-core |
Pack, Values, Archive, Manifest, Files | 65 |
sherpack-engine |
MiniJinja templating, filters, functions, subcharts | 118 |
sherpack-convert |
Helm Go templates → Jinja2 converter | 62 |
sherpack-kube |
Kubernetes, storage, hooks, CRD handling | 219 |
sherpack-repo |
Repository backends, dependencies, search | 53 |
sherpack-cli |
CLI application | 83 |
| Total | ~35k lines of Rust | 600 |
# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ release.name }}
labels:
app.kubernetes.io/name: {{ release.name }}
app.kubernetes.io/version: {{ pack.version }}
annotations:
checksum/config: {{ values.config | tojson | sha256 | trunc(16) }}
spec:
replicas: {{ values.replicas }}
selector:
matchLabels:
app.kubernetes.io/name: {{ release.name }}
template:
spec:
containers:
- name: app
image: {{ values.image.repository }}:{{ values.image.tag }}
envFrom:
- configMapRef:
name: {{ release.name }}-config
resources:
{{ values.resources | toyaml | nindent(12) }}
---
# templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ release.name }}-config
data:
{% for key, value in values.env | dictsort %}
{{ key }}: {{ value | quote }}
{% endfor %}{% if values.ingress.enabled %}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ release.name }}
annotations:
{% if values.ingress.tls %}
cert-manager.io/cluster-issuer: letsencrypt
{% endif %}
spec:
{% if values.ingress.tls %}
tls:
- hosts: {{ values.ingress.hosts | tojson }}
secretName: {{ release.name }}-tls
{% endif %}
rules:
{% for host in values.ingress.hosts %}
- host: {{ host }}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: {{ release.name }}
port:
number: 80
{% endfor %}
{% endif %}# Build
cargo build --workspace
# Test
cargo test --workspace
# Lint
cargo clippy --workspace
# Format
cargo fmt --all
# Run CLI
cargo run -p sherpack -- <command>Apache-2.0
Made with Rust