Skip to main content
Helm charts package Kubernetes manifests and configuration into a reusable deployment unit.
Permify publishes an official chart here: Permify Helm Charts.

Requirements

  • A Kubernetes cluster
  • kubectl configured for that cluster
  • Helm 3 installed (Helm install docs)

Add Permify Helm repository

helm repo add permify https://permify.github.io/helm-charts
helm repo update
helm search repo permify

Download and edit values.yaml

Before install, review and customize your chart values.
curl -o values.yaml https://raw.githubusercontent.com/Permify/helm-charts/main/charts/permify/values.yaml
You can also inspect defaults directly with Helm:
helm show values permify/permify
For advanced customization, you can inspect how chart values map into Kubernetes manifests:

Install and upgrade

Install with your customized values:
helm install permify permify/permify -f values.yaml
Upgrade an existing release:
helm upgrade permify permify/permify -f values.yaml
Check rollout:
kubectl get deployments,pods,svc

Helm Chart Configuration

Before you install, configure your values.yaml. The snippets below mirror the chart values and document each parameter inline.

Deployment and image settings

# replicaCount -- Number of Permify pods to run. Increase for high availability and throughput.
replicaCount: 3

image:
  # image.repository -- Container image repository for Permify.
  repository: ghcr.io/permify/permify
  # image.pullPolicy -- Image pull behavior. Always checks for newer image at pod start.
  pullPolicy: Always
  # image.tag -- Image tag override. For this guide, Permify version 1.6.0 is used
  tag: v1.6.0

Health checks

livenessProbe:
  # livenessProbe.enabled -- Enable liveness checks. Failed checks trigger container restart.
  enabled: true
  # livenessProbe.initialDelaySeconds -- Delay before first liveness check.
  initialDelaySeconds: 60
  # livenessProbe.periodSeconds -- Frequency of liveness checks.
  periodSeconds: 10
  # livenessProbe.timeoutSeconds -- Timeout per liveness check.
  timeoutSeconds: 5
  # livenessProbe.failureThreshold -- Consecutive failures before restart.
  failureThreshold: 12
  # livenessProbe.successThreshold -- Consecutive successes needed to mark healthy.
  successThreshold: 1

readinessProbe:
  # readinessProbe.enabled -- Enable readiness checks. NotReady pods are removed from service endpoints.
  enabled: true
  # readinessProbe.initialDelaySeconds -- Delay before first readiness check.
  initialDelaySeconds: 5
  # readinessProbe.periodSeconds -- Frequency of readiness checks.
  periodSeconds: 10
  # readinessProbe.timeoutSeconds -- Timeout per readiness check.
  timeoutSeconds: 5
  # readinessProbe.failureThreshold -- Consecutive failures before pod is marked NotReady.
  failureThreshold: 6
  # readinessProbe.successThreshold -- Consecutive successes to mark Ready.
  successThreshold: 1

startupProbe:
  # startupProbe.enabled -- Enable startup checks for slower boot scenarios.
  enabled: false
  # startupProbe.initialDelaySeconds -- Delay before first startup check.
  initialDelaySeconds: 60
  # startupProbe.periodSeconds -- Frequency of startup checks.
  periodSeconds: 10
  # startupProbe.timeoutSeconds -- Timeout per startup check.
  timeoutSeconds: 5
  # startupProbe.failureThreshold -- Consecutive failures before restart during startup phase.
  failureThreshold: 30
  # startupProbe.successThreshold -- Consecutive successes needed to pass startup phase.
  successThreshold: 1

# customLivenessProbe -- Full custom probe object. Overrides chart default liveness probe when set.
customLivenessProbe: {}
# customReadinessProbe -- Full custom probe object. Overrides chart default readiness probe when set.
customReadinessProbe: {}
# customStartupProbe -- Full custom probe object. Overrides chart default startup probe when set.
customStartupProbe: {}

Service and ingress

service:
  # service.type -- Service exposure type: ClusterIP, NodePort, or LoadBalancer.
  type: LoadBalancer
  # service.annotations -- Annotations on Kubernetes Service resource.
  annotations: {}

ingress:
  # ingress.enabled -- Create ingress resources for external HTTP(S) access.
  enabled: false
  # ingress.className -- Ingress class to target (for example nginx).
  className: ""
  # ingress.annotations -- Ingress-controller-specific annotations.
  annotations: {}
  hosts:
    - # ingress.hosts[].host -- Hostname routed to Permify service.
      host: chart-example.local
      paths:
        - # ingress.hosts[].paths[].path -- URL path for route matching.
          path: /
          # ingress.hosts[].paths[].pathType -- Path matching mode (ImplementationSpecific, Prefix, Exact).
          pathType: ImplementationSpecific
  # ingress.tls -- TLS host/secret mappings for HTTPS termination.
  tls: []

Permify application configuration (app)

app:
  # app.account_id -- Optional account identifier for runtime/account-scoped behavior.
  account_id: ""

  server:
    # app.server.rate_limit -- Server request rate limit.
    rate_limit: 100_000
    http:
      # app.server.http.enabled -- Enable HTTP API listener.
      enabled: true
      # app.server.http.port -- HTTP listener port.
      port: 3476
      tls:
        # app.server.http.tls.enabled -- Enable TLS for HTTP endpoint.
        enabled: false
    grpc:
      # app.server.grpc.port -- gRPC listener port.
      port: 3478
      tls:
        # app.server.grpc.tls.enabled -- Enable TLS for gRPC endpoint.
        enabled: false

  logger:
    # app.logger.level -- Log verbosity (error, warn, info, debug).
    level: info

  profiler:
    # app.profiler.enabled -- Enable pprof profiling endpoint.
    enabled: true
    # app.profiler.port -- pprof server port.
    port: 6060

  authn:
    # app.authn.enabled -- Enable API authentication.
    enabled: false
    # app.authn.method -- Authentication method (for example preshared).
    method: preshared
    preshared:
      # app.authn.preshared.keys_secret -- Optional secret reference for preshared keys.
      # keys_secret:
      # app.authn.preshared.keys -- Inline preshared keys accepted by the API.
      keys: ["secret"]

  tracer:
    # app.tracer.enabled -- Enable distributed tracing export.
    enabled: false

  meter:
    # app.meter.enabled -- Enable metrics export.
    enabled: false
    # app.meter.exporter -- Metrics exporter type.
    exporter: otlp
    # app.meter.endpoint -- Metrics exporter endpoint.
    endpoint: telemetry.permify.co

  service:
    # app.service.circuit_breaker -- Enable circuit breaker behavior for internal operations.
    circuit_breaker: false
    watch:
      # app.service.watch.enabled -- Enable watch/change-stream behavior.
      enabled: false
    schema:
      cache:
        # app.service.schema.cache.number_of_counters -- Counter count used by schema cache policy.
        number_of_counters: 1_000
        # app.service.schema.cache.max_cost -- Memory budget for schema cache.
        max_cost: 8MiB
    permission:
      # app.service.permission.concurrency_limit -- Limit concurrent permission evaluations.
      concurrency_limit: 100
      cache:
        # app.service.permission.cache.number_of_counters -- Counter count used by permission cache policy.
        number_of_counters: 10_000
        # app.service.permission.cache.max_cost -- Memory budget for permission cache.
        max_cost: 16MiB

Database and distributed mode

app:
  database:
    # app.database.engine -- Storage backend. 'memory' is ephemeral; 'postgres' is persistent.
    engine: postgres
    # app.database.uri -- PostgreSQL connection URI.
    uri: postgres://postgres:secret@localhost:5432/permify?sslmode=disable
    # app.database.uri_secret -- If you use a secret to store the database URI, set it here.
    #uri_secret: ""
    # app.database.auto_migrate -- Run schema migrations automatically at startup.
    auto_migrate: true
    # app.database.max_open_connections -- Max DB connections.
    max_open_connections: 20
    # app.database.max_idle_connections -- Max idle DB connections.
    max_idle_connections: 1
    # app.database.max_connection_lifetime -- Max lifetime for DB connections.
    max_connection_lifetime: 300s
    # app.database.max_connection_idle_time -- Max idle time before DB connection is closed.
    max_connection_idle_time: 60s
   
    garbage_collection:
      # app.database.garbage_collection.enabled -- Enable stale tuple cleanup jobs.
      enabled: false
      # app.database.garbage_collection.interval -- GC run interval.
      # interval: 200h
      # app.database.garbage_collection.window -- GC lookback window.
      # window: 200h
      # app.database.garbage_collection.timeout -- Timeout per GC run.
      # timeout: 5m

  distributed:
    # app.distributed.enabled -- Enable distributed mode across multiple instances.
    enabled: false

Resources, database job, autoscaling, and scheduling

# resources -- CPU/memory requests and limits for the Permify container.
# Setting requests/limits strongly affects scheduling, stability, and autoscaling behavior.
resources: {}

autoscaling:
  # autoscaling.enabled -- Enable HorizontalPodAutoscaler for Permify deployment.
  enabled: false
  # autoscaling.minReplicas -- Minimum number of replicas when autoscaling is enabled.
  minReplicas: 1
  # autoscaling.maxReplicas -- Maximum number of replicas when autoscaling is enabled.
  maxReplicas: 100
  # autoscaling.targetCPUUtilizationPercentage -- CPU utilization target for HPA scaling decisions.
  targetCPUUtilizationPercentage: 80
  # autoscaling.targetMemoryUtilizationPercentage -- Memory utilization target for HPA scaling decisions.
  targetMemoryUtilizationPercentage: 80

# nodeSelector -- Constrain pod placement to nodes with matching labels.
nodeSelector: {}
# tolerations -- Allow scheduling onto tainted nodes.
tolerations: []
# affinity -- Advanced pod scheduling rules (node affinity, pod affinity/anti-affinity).
affinity: {}

Production notes

  • Set app.authn.enabled: true and supply keys via secret-based settings in production.
  • If you expose Permify externally, either configure ingress and TLS or use a LoadBalancer-type service.