Navidrome on GKE Autopilot
Navidrome is a free, open-source, self-hosted music streaming server written in Go. It exposes a Subsonic/OpenSubsonic-compatible API (so any Subsonic client — DSub, Symfonium, Sublime Music, play:Sub, etc. — can browse and stream your library) plus its own web UI, and stores its state in an embedded SQLite database rather than a managed SQL backend. This module deploys Navidrome on GKE Autopilot on top of the App_GKE foundation, which provisions and manages the shared Google Cloud and Kubernetes infrastructure.
This guide focuses on the cloud services Navidrome uses and how to explore and operate them from the Google Cloud Console and the command line. For the mechanics that are common to every GKE application — Workload Identity, ingress, autoscaling, CI/CD, Cloud Armor, IAP, Binary Authorization, VPC Service Controls, backups, and the deployment lifecycle — refer to the App_GKE foundation guide rather than repeating them here.
What Navidrome costs on RAD, and how that compares
Navidrome on RAD's GKE Autopilot module costs about US$42–115 a month, with the module fee charged once in RAD credits. GKE Autopilot suits Navidrome that must stay up, scale across pods or run beside other Kubernetes workloads; for the lowest cost, the Cloud Run module runs the same Navidrome for about US$33 a month. If you only need it occasionally — a demo, a seasonal project, something you're evaluating — a RAD-managed project can be deleted and restored within 30 days for a handful of credits (under US$1) instead of paying for it to sit idle. See Pause it for free, below. Figures are as at 8 October 2026; sources are listed at the end of this section.
What you pay on RAD
RAD deploys Navidrome, which is open source, so there is no licence fee per user. You pay for three things:
| In a Google Cloud project you own | In a project RAD manages for you | |
|---|---|---|
| Module fee, once per deployment | 75 credits (US$8 at the top-up price) | 67.5 credits (10% lower) |
| Build time | About 3-6 credits per build | The same |
| Google Cloud running cost | Billed by Google to your own billing account, about US$42 a month for the default configuration (table below) — more if this isn't your only Autopilot cluster | Metered hourly in credits; RAD publishes 67 credits a day, about 2,010 a month (about US$201 at the top-up price, US$161 at the Scale plan's rate) |
| Who owns what | You own the project and its billing; RAD deploys and updates it | RAD owns the project, with guardrails, quotas and budget alerts; you get console access, and a minimum purchased balance is held in reserve |
10 credits cost US$1 on a one-off top-up, and less on a monthly plan. In a project RAD manages, the database, file server and network are shared by every application in the project, so a second application does not add a second set of them.
Default running cost in your own project (us-central1, Google list prices):
| Resource (module default) | Per month |
|---|---|
| GKE Autopilot pod, 1x vCPU / 1 GiB | US$36.08 |
| Cloud NAT and networking | US$5 |
| Cloud Storage (add-ons, backups) | US$1 |
| GKE cluster management fee | shared across every GKE app in the project; $0 if this is your only cluster, else ~73 |
| Total | about US$42 (about US$115 if this isn't your only Autopilot cluster) |
How it compares
- No turnkey managed SaaS was verified for Navidrome itself, so the honest comparison is a self-managed server: a Hetzner CPX22 (2 vCPU/4 GB) costs about $24/month, a DigitalOcean 2 vCPU/4 GB Droplet about $24/month, and a GCP Compute Engine e2-standard-2 (2 vCPU/8 GB) about $49/month.
- This is a light workload — a cheaper, smaller VPS class than the reference boxes below would also do the job; the figures are shown for a like-for-like comparison.
- This is a personal music server, not a team product with a licensed SaaS competitor — the comparison that matters is self-hosting it yourself versus letting RAD manage the project, not RAD versus a streaming subscription (a streaming service doesn't host your own library).
- The VPS price is not the whole cost. On a bare VPS you are also the one patching the OS, rotating backups and keeping the database (if any) healthy. RAD's managed Cloud SQL, Secret Manager and monitoring cover that for you, which is the real argument for RAD over a cheaper box — not the sticker price.
Pause it for free: delete a RAD-managed project, restore it when you need it
If Navidrome runs in a project RAD manages for you, you have a second option that goes well beyond scaling to zero: delete the whole project, and restore it within 30 days for close to nothing. This suits Navidrome you only need occasionally — a demo, an evaluation, a seasonal project — far better than running it continuously.
- How it works. Deleting a RAD-managed project unlinks its billing first, then asks Google to delete the project. Google does not remove the project immediately: it keeps it, recoverable, for 30 days. Because billing is already unlinked, nothing is charged while it waits. Unlike deleting one module, this does not tear down the cluster or the compute resource one by one — the whole project, and everything in it, simply stops.
- Restoring costs a few credits, not a rebuild. Within 30 days, the project's owner can restore it. RAD asks Google to undelete the project and reattaches its billing account, then asks you to run Update on each deployment to confirm everything came back. Because nothing was individually destroyed, that Update finds the same resources already there — it is a check, not a rebuild, and an Update never charges the module fee again. That costs roughly a handful of credits (under US$1) in total for a typical 2-3-deployment chain.
- So a month of occasional use can cost a few dollars, not US$42. Deploy Navidrome, use it for a while, delete the project. Restore it next time you want it, confirm with Update, and delete it again when you're done. You pay only for the module fee once, the builds, and whatever time Navidrome was actually live.
- What this needs. You must own the project (not a bring-your-own one RAD only manages billing for), and you restore it yourself within the 30 days — after that, Google deletes it for good. Restoring is admitted like creating a new project: your purchased credit balance must still clear the tier's floor (100 credits for the sandbox tier most study and demo use fits). Google says most services are fully working again within 36 hours of a restore.
- One real gap: nightly backups don't survive. Backups are written to a bucket inside the project, and that bucket is not protected by Cloud Storage's soft-delete, so it is very likely gone as soon as you delete the project — even though the project itself is recoverable for 30 days. If you've customised Navidrome and want to keep that work, copy a backup out (to Google Drive, or a bucket outside the project) before you delete. For a default installation with nothing irreplaceable in it, this does not matter.
Pay only while you use it, the other way: delete and redeploy
The option above only applies to a RAD-managed project; in your own project, or once the 30-day window has passed, the way to stop paying is to delete the deployment and deploy it again when you need it.
- What a redeploy costs. The module fee again plus the builds: about 80 credits (US$8) in your own project, or 72 credits in a RAD-managed one. Deleting saves money once Navidrome would otherwise sit unused for about 6 days or more in your own project (about US$1.40 a day), or about 1 days or more in a RAD-managed one (67 credits a day).
- Most of the running cost is usually the database and any shared file/cache VM. They stop only when nothing else in the project uses them, so deleting Navidrome while something else shares the project saves only this app's own compute part.
- Keep your data first. Nightly backups go to a bucket inside the deployment and are deleted with it, so copy the latest backup out before deleting if you want to keep it.
Lab sessions and Managed Environments
- Lab sessions, for training. A trainer runs a session for a class. Each participant gets Navidrome in their own Google Cloud project for 15 minutes to 24 hours, within an allowance the trainer sets. Either the trainer funds every place, or each participant pays for their own. Everything is deleted when the session ends and unused credits go back to the trainer.
- Managed Environments, for consultancies. A partner runs Navidrome for a client from a ring-fenced wallet it funds, and settles with the client directly. If the wallet runs low, billing pauses and the data is kept, so nobody receives an unexpected charge. At the end the partner hands the project over and the deployments become the client's own.
- Credits can be bought in more than 20 currencies, including XAF, XOF, NGN, GHS, KES and ZAR, by card, bank transfer or mobile money.
Sources (8 October 2026): Google Cloud list prices from the Cloud Billing Catalog API; Delete and restore projects for the 30-day recovery window and what it says about Cloud Storage objects without soft delete; RAD fees and the daily-credit estimates from radmodules.dev/pricing. Prices change; check each source before relying on a figure.
1. Overview
Navidrome runs as a single Go binary serving HTTP on one port. Because it has no external database, the deployment wires together a narrower set of Google Cloud services than a typical database-backed app:
| Capability | Google Cloud service | Notes |
|---|---|---|
| Compute | GKE Autopilot | A StatefulSet pod on port 4533, 1 vCPU / 1 GiB by default |
| Application data | Block-storage PVC (Persistent Disk, via stateful_pvc_enabled) | Backs the embedded SQLite DB, artwork cache, and search index at /data — not Cloud SQL |
| Music library | Operator-supplied GCS FUSE volume or Cloud Filestore (NFS) at /music | Read-only source audio files; not provisioned automatically |
| Object storage | Cloud Storage | A storage bucket is always created but sits unmounted while the default block PVC handles /data |
| Secrets | Secret Manager | An auto-generated admin password (ND_DEVAUTOCREATEADMINPASSWORD), injected as a native Kubernetes Secret |
| Ingress | Kubernetes Gateway API / ClusterIP | No LoadBalancer by default — internal-only until a custom domain or service_type change is configured |
Sensible defaults worth knowing up front:
- No SQL database.
database_typeis fixed toNONEbyNavidrome_Common; everydb_*/database_*/sql_instance_*variable in this module is forwarded to the foundation only for structural compatibility and has no effect. - SQLite needs a real block PVC, not
gcsfuse. Per this repository's storage convention,gcsfusecannot safely back SQLite's write-locking model. GKE gives Navidrome a genuine advantage over the Cloud Run variant here:stateful_pvc_enableddefaults totrue, provisioning a per-pod Persistent Disk mounted at/data(ND_DATAFOLDER) that holds the SQLite database, artwork cache, and search index. This auto-resolves the workload to aStatefulSet. - The PVC storage class defaults to
standard-rwo(SSD Balanced PD). This draws the tightSSD_TOTAL_GBregional quota documented in this repo's storage conventions. Navidrome's data directory is metadata/index-sized, not bulk-media-sized, so SSD is reasonable here — but on a quota-constrained project consider-var stateful_pvc_storage_class=standard(HDDpd-standard) if you hitQuota 'SSD_TOTAL_GB' exceededacross a wider campaign of stateful apps. - The music library is not mounted automatically.
ND_MUSICFOLDER=/musicis set as an env var, but no volume is attached to/musicout of the box — you must add a read-only GCS FUSE volume (gcs_volumes) or an NFS mount (enable_nfs = true,nfs_mount_path = "/music") pointing at your source audio files. Unlike/data,/musicis read-only and holds no SQLite state, sogcsfuseis fine for it. - Single replica by default.
min_instance_count = 1,max_instance_count = 1. Navidrome serves one shared SQLite library from one PVC; there is no multi-writer/clustering mode, so do not scale beyond 1. - No external ingress by default.
service_type = "ClusterIP"andenable_custom_domain = truebut with an emptyapplication_domainslist — so out of the box Navidrome is reachable only inside the cluster/VPC. Setapplication_domains(Gateway + managed cert) or switchservice_typetoLoadBalancerto expose it externally. - Admin account is auto-created.
enable_admin_password = truegenerates a random password, stores it in Secret Manager, and injects it asND_DEVAUTOCREATEADMINPASSWORDso Navidrome creates theadminuser on first boot. Set it tofalseto use the first-run web setup wizard instead. - Health probes hit the public
GET /pingendpoint (returns{"status":"ok"}, no auth required).
2. Google Cloud Services & How to Explore Them
All commands assume you have run
gcloud container clusters get-credentials <cluster> --region "$REGION" --project "$PROJECT"
and that PROJECT, REGION, and NAMESPACE are set. The namespace and other
identifiers are reported in the deployment Outputs.
A. GKE Autopilot — the Navidrome StatefulSet
With the default stateful_pvc_enabled = true, Navidrome deploys as a
StatefulSet (not a Deployment) so its single pod keeps a stable identity and a
PVC that survives reschedules. Autopilot bills for the CPU/memory the pod actually
requests.
- Console: Kubernetes Engine → Workloads → select the Navidrome workload for
pods, revisions, and events. Confirm the workload type reads
StatefulSet. - CLI:
kubectl get statefulset,pods,svc -n "$NAMESPACE"
kubectl logs -n "$NAMESPACE" statefulset/<service-name> --tail=100
kubectl describe pod -n "$NAMESPACE" -l app=<service-name>
See App_GKE for how Autopilot scheduling and the
StatefulSet-vs-Deployment auto-resolution work in general.
B. Block-storage PVC — the SQLite data volume
The per-pod PersistentVolumeClaim at /data is the single source of truth for
Navidrome: the SQLite database, the metadata/artwork cache, transcode temp files
(if enabled), and the search index all live here. Losing this PVC loses your
library metadata, playlists, ratings, and users (the source audio itself is
unaffected, since /music is a separate, operator-supplied mount).
- Console: Kubernetes Engine → Storage → PersistentVolumeClaims and PersistentVolumes; Compute Engine → Disks to see the underlying Persistent Disk.
- CLI:
kubectl get pvc -n "$NAMESPACE"
kubectl describe pvc -n "$NAMESPACE" -l app=<service-name>
gcloud compute disks list --project "$PROJECT" --filter="name~<service-name>"
See App_GKE Group 7 for the full stateful_pvc_* mechanics
(storage class, pod management policy, update strategy).
C. Music library storage (GCS FUSE or NFS)
/music is where Navidrome scans for audio files. Nothing is mounted there by
default — wire up either a read-only GCS FUSE volume (gcs_volumes, CSI
driver-backed, fine here since /music holds no SQLite state) pointing at a bucket
of uploaded audio, or a Cloud Filestore (NFS) share (enable_nfs = true,
nfs_mount_path = "/music") if you need write access from another host to add
files. A separate, always-created storage GCS bucket exists for compatibility
with the Cloud Run variant but sits unmounted while the block PVC serves /data.
- Console: Cloud Storage → Buckets; Filestore → Instances.
- CLI:
gcloud storage buckets list --project "$PROJECT" --filter="name~<service-name>"
gcloud filestore instances list --project "$PROJECT"
kubectl exec -n "$NAMESPACE" statefulset/<service-name> -- ls /music
See App_GKE Groups 13–14 for NFS and GCS Fuse volume mechanics.
D. Secret Manager
One secret is generated automatically: the admin password, stored under
secret-<prefix>-navidrome-admin-password and injected into the pod as a native
Kubernetes Secret (not via the Secret Store CSI driver) for the env var
ND_DEVAUTOCREATEADMINPASSWORD, which Navidrome reads on first boot to create the
admin account.
- Console: Security → Secret Manager.
- CLI:
gcloud secrets list --project "$PROJECT" --filter="name~navidrome-admin-password"
gcloud secrets versions access latest --secret=<admin-password-secret-name> --project "$PROJECT"
See App_GKE for the general Secret Manager / Secret Store CSI integration used by other apps' secrets.
E. Networking & ingress
By default service_type = "ClusterIP" and application_domains is empty, so
Navidrome is reachable only from inside the VPC/cluster
(http://<service>.<namespace>.svc.cluster.local). Set application_domains (with
enable_custom_domain = true, already the module default) to provision a
Kubernetes Gateway with a managed TLS certificate, or switch service_type to
LoadBalancer for a plain external IP.
- Console: Kubernetes Engine → Services & Ingress; Network services → Load balancing; VPC network → IP addresses.
- CLI:
kubectl get svc,gateway -n "$NAMESPACE"
gcloud compute addresses list --project "$PROJECT"
See App_GKE Group 19 for the Gateway API, static IP, and default
nip.io hostname mechanics.
F. Cloud Logging & Monitoring
Pod stdout/stderr flow to Cloud Logging; GKE metrics flow to Cloud Monitoring.
Optional uptime checks and alert policies are available (uptime_check_config
defaults to false).
- Console: Logging → Logs Explorer; Monitoring → Dashboards / Alerting.
- CLI:
gcloud logging read 'resource.type="k8s_container" AND resource.labels.namespace_name="'"$NAMESPACE"'"' \
--project "$PROJECT" --limit 50
3. Navidrome Application Behaviour
- No init/migration job. Navidrome has no external database, so there is no
db-initor migration Job — the SQLite schema is created by the binary itself on first start against the empty/dataPVC.initialization_jobsdefaults to[]and is only for custom, operator-supplied tasks. - Admin bootstrap. With
enable_admin_password = true(default), the container starts withND_DEVAUTOCREATEADMINPASSWORDset from the generated secret, and Navidrome auto-creates theadminuser with that password on first boot. Withenable_admin_password = false, the first person to open the web UI completes the setup wizard and chooses their own admin credentials — recommended only for cluster-internal, trusted-access deployments. - Immutable-ish PVC identity. Because the pod is a
StatefulSet, the PVC is bound to the pod's stable identity (<service-name>-0) and survives pod reschedules/restarts. Scalingmax_instance_countbeyond 1 is not supported — Navidrome has no multi-writer SQLite mode. - Health path. Both the startup probe and the liveness probe are HTTP
GET /ping, an unauthenticated endpoint returning{"status":"ok"}. Allow a few minutes on first boot while the library scan runs (large libraries take longer). - Library scan. Navidrome scans
/musicon startup and on a periodic schedule thereafter; scan progress and results are visible in pod logs and the web UI. - Verify the running config and library mount:
kubectl exec -n "$NAMESPACE" statefulset/<service-name> -- env | grep ^ND_
kubectl exec -n "$NAMESPACE" statefulset/<service-name> -- ls /music
kubectl logs -n "$NAMESPACE" statefulset/<service-name> --tail=50 | grep -i scan
4. Configuration Variables
Variables are grouped exactly as they appear on the deployment platform. Only settings specific to or notable for Navidrome are listed; every other input is inherited from App_GKE with its standard behaviour and defaults.
Group 3 — Application Identity
| Variable | Default | Description |
|---|---|---|
application_name | navidrome | Base name for resources. Do not change after first deploy. |
application_version | latest | deluan/navidrome image tag used as the custom-build base; latest is pinned to a known-good tag (0.54.3) at build time. |
application_display_name | Navidrome Music Server | Human-readable name shown in the platform UI. |
enable_admin_password | true | Auto-generates the admin password and creates the admin user on first boot via ND_DEVAUTOCREATEADMINPASSWORD. Set false to use the first-run web wizard instead. |
Group 4 — Runtime & Scaling
| Variable | Default | Description |
|---|---|---|
cpu_limit | 1000m | 1 vCPU; raise for on-the-fly transcoding, which is CPU-bound. |
memory_limit | 1Gi | Navidrome holds its search index in memory; size to library scale. |
min_instance_count | 1 | Keep at 1 — avoids cold starts during index/library loading. |
max_instance_count | 1 | Keep at 1. No multi-writer SQLite support. |
enable_cloudsql_volume | false | Navidrome has no Cloud SQL database — keep false. |
Group 6 — GKE Backend & Cluster
| Variable | Default | Description |
|---|---|---|
workload_type | null → StatefulSet | Auto-resolves to StatefulSet because stateful_pvc_enabled = true. |
service_type | LoadBalancer | Externally reachable by default — an external IP is provisioned. Set ClusterIP for internal-only access, in which case reach it via a custom domain or kubectl port-forward. |
session_affinity | None | No sticky routing needed with a single replica. |
Group 7 — StatefulSet / PVC
| Variable | Default | Description |
|---|---|---|
stateful_pvc_enabled | true | Provisions a real block PVC at /data — required so gcsfuse never backs the embedded SQLite DB. |
stateful_pvc_size | 20Gi | Sized for the SQLite DB, metadata cache, and search index (not the music library, which mounts separately). |
stateful_pvc_mount_path | /data | Must match Navidrome's ND_DATAFOLDER. |
stateful_pvc_storage_class | standard-rwo | SSD Balanced PD by default; switch to standard (HDD) if SSD_TOTAL_GB quota is constrained. |
stateful_fs_group | 3000 | Matches the Navidrome Helm chart's UID 1000/GID 2000 convention, ensuring the PVC is group-writable. |
Group 13 — NFS Storage
| Variable | Default | Description |
|---|---|---|
enable_nfs | false | Enable and set nfs_mount_path = "/music" to mount a writable, shared music library via Cloud Filestore. |
nfs_mount_path | /mnt/nfs | Not /music by default — must be overridden if using NFS for the library. |
Group 14 — Cloud Storage
| Variable | Default | Description |
|---|---|---|
create_cloud_storage | true | Always creates the storage bucket; it stays unmounted while the default block PVC serves /data. |
gcs_volumes | [] | Add a read-only entry with mount_path = "/music" to source your library from GCS instead of NFS. |
Group 16 — Database Configuration
| Variable | Default | Description |
|---|---|---|
database_type | NONE | Fixed by Navidrome_Common — Navidrome has no SQL database; every other database_*/sql_* variable is inert. |
Group 19 — Custom Domain, Static IP & Networking
| Variable | Default | Description |
|---|---|---|
enable_custom_domain | true | Provisions the Gateway resource, but has no effect until application_domains is non-empty. |
application_domains | [] | Set to expose Navidrome externally via Gateway + managed certificate. |
reserve_static_ip | true | Stable IP once external ingress (LoadBalancer or Gateway) is configured. |
All other inputs follow standard App_GKE behaviour.
5. Outputs
These values are returned on a successful deployment and are the quickest way to locate and explore the running resources.
| Output | Description |
|---|---|
service_name | Kubernetes Service name. |
namespace | Namespace the workload runs in. |
service_cluster_ip | In-cluster ClusterIP. |
stage_service_cluster_ips | Map of ClusterIPs for stage-specific services. |
service_external_ip | External LoadBalancer IP (when service_type = LoadBalancer and a static IP is reserved). |
service_url | URL to reach Navidrome. |
navidrome_admin_password_secret_id | Secret Manager secret ID for the generated admin password (empty when enable_admin_password = false). |
storage_buckets | Created Cloud Storage buckets. |
network_name / network_exists / regions | VPC network, presence, available regions. |
container_image / container_registry | Deployed image and Artifact Registry repo. |
monitoring_enabled / monitoring_notification_channels | Monitoring status and channels. |
deployment_id / tenant_id / resource_prefix | Naming identifiers. |
project_id / project_number | Project identifiers. |
initialization_jobs | Names of any operator-supplied initialization jobs. |
statefulset_name | Name of the StatefulSet. |
cicd_enabled / cicd_configuration | CI/CD status and details (repo, trigger, registry). |
github_repository_url / github_repository_owner / github_repository_name | CI/CD GitHub details. |
artifact_registry_repository / cloudbuild_trigger_name / cloudbuild_trigger_id | Registry and build trigger. |
kubernetes_ready | Whether the cluster/workload is ready. |
vpc_sc_enabled / vpc_sc_perimeter_name / vpc_sc_dry_run_mode | VPC-SC status. |
audit_logging_enabled / artifact_registry_cmek_enabled | Audit logging and CMEK status. |
6. Configuration Pitfalls & Sensible Defaults
Risk: Critical (data loss / outage / security) — High (service degraded) — Medium (cost or partial degradation) — Low (minor).
Inherited plan-time validation. This module passes its configuration through the App_GKE foundation engine, which validates values and combinations at plan time — a
StatefulSetforced alongside a stateless setting, IAP with no authorized identities,quota_memory_*given as bare integers, an out-of-rangecontainer_port/backup_retention_days. Invalid configuration fails the plan with a clear, named error before any resource is created, so most mistakes below are caught up front rather than at apply or runtime.
| Setting | Sensible value | Risk | Consequence if wrong |
|---|---|---|---|
stateful_pvc_enabled | true | Critical | Disabling it (or otherwise backing /data with gcsfuse) risks corrupting SQLite's write-locking model — DB corruption, lost library metadata. |
stateful_pvc_storage_class | standard-rwo (or standard under quota pressure) | High | SSD draws the tight SSD_TOTAL_GB regional quota; a wide campaign of stateful apps can exhaust it — switch to HDD standard if so. |
max_instance_count | 1 | Critical | Navidrome has no multi-writer SQLite mode; scaling beyond 1 risks concurrent writes to the same PVC and DB corruption. |
/music volume (gcs_volumes or enable_nfs) | Configure explicitly | High | Nothing is mounted at /music by default — the library scan finds no files and Navidrome serves an empty catalogue until a volume is added. |
enable_admin_password | true for any externally reachable deployment | High | false leaves the first-run wizard exposed to whoever reaches the URL first — they become admin. |
application_domains / service_type | Set one to expose externally | Medium | The default ClusterIP + empty application_domains leaves Navidrome reachable only inside the VPC — expected for internal use, surprising if you wanted public access. |
stateful_pvc_size | 20Gi (raise for very large libraries) | Medium | Undersizing risks the SQLite DB/cache/index filling the PVC on large libraries; the pod does not auto-expand storage. |
quota_cpu_requests / quota_memory_requests / etc. | N/A | Low | These quota_* variables are declared but not forwarded to the foundation by this module — setting them has no effect; only enable_resource_quota is wired through (falling back to App_GKE's own quota defaults). |
memory_limit | 1Gi | Medium | Below ~512Mi the pod risks OOM while holding the search index in memory during a large library scan. |
stateful_fs_group | 3000 | Medium | A mismatched fsGroup can leave the PVC unwritable by Navidrome's non-root UID, blocking DB writes at boot. |
backup_retention_days | 7 (raise for prod) | Low | Too short for compliance retention of /data backups. |
For the foundation behaviour referenced throughout — IAM and Workload Identity, autoscaling, ingress and certificates, CI/CD, Cloud Armor, IAP, Binary Authorization, VPC-SC, backups, and image mirroring — see App_GKE. Navidrome-specific application configuration shared with the Cloud Run variant is described in Navidrome_Common.
Related guides
- Hands-on lab: Navidrome on GKE Autopilot — deploy it step by step, with the console screens and commands at each stage.
- Navidrome on Google Cloud Run — the same application on Cloud Run, for when you need the other deployment target.
- Navidrome Common — Shared Application Configuration — the configuration shared by both deployment targets.
- Deployed alongside Calibre-Web on GKE Autopilot, Komga on GKE Autopilot, Kavita on GKE Autopilot, Audiobookshelf on GKE Autopilot in the Digital Library solution.
Need RAD to do something it does not do yet? Request it on the roadmap, or vote on what is already there.