RomM
A self-hosted ROM manager with metadata enrichment and a clean web UI.
RomM is an open-source ROM manager that scans your game collection, enriches it with metadata from IGDB and MobyGames, and provides a clean web interface to browse and download ROMs. It supports multiple platforms and naming schemes. Self-hosting avoids cloud ROM storage services and keeps your game collection organized and accessible.
Alternatives considered
Self Hosted
| Tool | Open Source | Full Features | Notes |
|---|---|---|---|
| LaunchBox | No | Limited | Windows desktop only; no web UI |
| Playnite | Yes | Yes | Local game library manager; no web access |
Installation
Architecture
- Deployment: Single
romm-deploydeployment in therommnamespace - Image:
rommapp/romm, digest-pinned via Renovate - Database: CNPG PostgreSQL cluster
cnpg(two instances onlonghorn-db-single-encrypted) - Storage: Longhorn PVCs for
assets,configandresources; NFS PV from TrueNAS for ROM library - Networking: ClusterIP service, HTTPRoute via internal gateway
Security
- No
runAsUseris set, so the container starts as the image's default user, which is root; privilege escalation is blocked and all capabilities are dropped - Longhorn PVCs encrypted at rest via SOPS-managed keys
Updates
Managed by Renovate. Image is digest-pinned.
Data Management
- Database: CNPG PostgreSQL cluster
cnpg - PVCs:
assetsandconfig(Longhorn-encrypted,k8up.io/backup: "true") - NFS: TrueNAS NFS PV for ROM library storage
- Backups: k8up
Schedules to Hetzner and Backblaze via restic, covering the assets, config and resources PVCs and the database dump from thebackups-cnpgPreBackupPod.
User Management
OIDC configured — OIDC_ENABLED, OIDC_PROVIDER, OIDC_CLIENT_ID, OIDC_CLIENT_SECRET, OIDC_REDIRECT_URI all from SOPS-encrypted secret. Provider is Keycloak.
Configuration Management
- OIDC credentials and database credentials from SOPS-encrypted secret
- Longhorn encryption keys from SOPS-encrypted secrets
Usage
Browse your ROM collection by platform in the web UI. RomM automatically matches ROMs to metadata from IGDB for cover art and descriptions. Download ROMs directly from the browser or connect emulators via the API. OIDC SSO is configured for single sign-on authentication.
Cluster-specific deviations from the above live in the per-cluster README — see k8s/apps/romm/talos/README.md.
Cluster Deployment
RomM — Talos cluster
- Image:
rommapp/romm:5.4.0@sha256:03295f95a6290e752641f9553ac4198b0e5b71b879d57f7b2371b98f608feb54
Rendered manifests (kustomize build)
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
kustomize.toolkit.fluxcd.io/force: enabled
labels:
app.kubernetes.io/name: romm
name: romm-deploy
namespace: romm
spec:
replicas: 1
revisionHistoryLimit: 2
selector:
matchLabels:
app.kubernetes.io/name: romm
strategy:
type: Recreate
template:
metadata:
labels:
app.kubernetes.io/name: romm
spec:
automountServiceAccountToken: false
containers:
- env:
- name: ROMM_DB_DRIVER
value: postgresql
- name: DB_HOST
valueFrom:
secretKeyRef:
key: host
name: cnpg-app
- name: DB_PORT
valueFrom:
secretKeyRef:
key: port
name: cnpg-app
- name: DB_NAME
valueFrom:
secretKeyRef:
key: dbname
name: cnpg-app
- name: DB_USER
valueFrom:
secretKeyRef:
key: user
name: cnpg-app
- name: DB_PASSWD
valueFrom:
secretKeyRef:
key: password
name: cnpg-app
envFrom:
- secretRef:
name: romm
image: rommapp/romm:5.4.0@sha256:03295f95a6290e752641f9553ac4198b0e5b71b879d57f7b2371b98f608feb54
name: romm
ports:
- containerPort: 8080
name: web
protocol: TCP
readinessProbe:
failureThreshold: 1
httpGet:
path: /
port: 8080
initialDelaySeconds: 10
periodSeconds: 3
successThreshold: 1
timeoutSeconds: 2
resources:
limits:
memory: 2816Mi
requests:
cpu: 75m
memory: 1408Mi
volumeMounts:
- mountPath: /romm/library/roms
name: roms
subPath: roms
- mountPath: /romm/library/bios
name: roms
subPath: bios
- mountPath: /romm/assets
name: assets
- mountPath: /romm/config
name: config
- mountPath: /romm/resources
name: resources
priorityClassName: tier-3
volumes:
- name: roms
persistentVolumeClaim:
claimName: romm-truenas-nfs-gaming
- name: config
persistentVolumeClaim:
claimName: config
- name: assets
persistentVolumeClaim:
claimName: assets
- name: resources
persistentVolumeClaim:
claimName: resources