MemKV
Get started

Quick Start

Install MemKV, initialize NVMe drives, and start the server.

Deployment shapes

MemKV runs in two shapes. Both use the same wire protocol, authentication, and license.

  • Distributed server (Linux). Several servers with NVMe drives and RDMA NICs. This is the shape for production performance, and the one benchmarked at 97.4 GB/s.
  • Co-located server. One MemKV server on the same host as the inference engine, such as a Linux GPU development box, an edge AI node, or an Apple Silicon Mac. It stores data in regular files and the engine connects over TCP on 127.0.0.1. On Linux, set storage.mode: file. On macOS this is the only shape, because RDMA, JBOF, and hugepages are not available there.

Requirements for the distributed server

  • Linux kernel 6.8 or later.
  • An RDMA NIC: Mellanox mlx5 with DC support for the fastest path, or any RoCE NIC.
  • NVMe drives used only by MemKV. memkv setup erases them.
  • Hugepages for the server's memory pool: at least memory.max_size worth of 2 MiB pages. Reserve them with sudo sysctl -w vm.nr_hugepages=N. memkv start refuses to start if free hugepage memory is smaller than the pool.
  • A MemKV Enterprise license.

Requirements for the co-located server

  • Linux 6.8 or later, or macOS 13 or later (Apple Silicon or Intel).
  • A regular disk for file-mode storage. RDMA, JBOF, and hugepages are not needed.
  • TCP transport only. Bandwidth is limited by the host file system and NIC.

For performance, use raw block devices (mode: direct) rather than file mode, in either shape. The 97.4 GB/s figure comes from the distributed shape on raw block devices over RDMA, so a co-located server on TCP does not reach it. File mode is for development and for hosts without raw drives to dedicate.

Run these steps on each MemKV server. One binary contains the server, the admin client, and the documentation site.

Download the binary

curl -LO https://dl.min.io/aistor/memkv/release/linux-amd64/memkv
chmod +x memkv
sudo mv memkv /usr/local/bin/
memkv --version

For Arm servers, replace linux-amd64 with linux-arm64 in the URL.

Provision a license

Request an Enterprise license at min.io/pricing and save the license file in /etc/memkv/:

sudo mkdir -p /etc/memkv
sudo install -m 0600 /path/to/minio.license /etc/memkv/minio.license

The server finds the license there. To use another path, set MEMKV_LICENSE.

Initialize drives

memkv setup prints the server configuration to stdout. Save it as your config file:

sudo memkv setup \
  --drives /dev/nvme0n1 /dev/nvme1n1 /dev/nvme2n1 \
  --rdma mlx5_0 \
  | sudo tee /etc/memkv/config.yaml

The CLI reference lists every flag.

memkv setup reformats the listed drives and destroys all data on them. To reformat a drive that MemKV already initialized, add --force.

Start the server

sudo memkv start --config /etc/memkv/config.yaml

The server listens on TCP port 9900 for clients and on HTTP port 9901 for admin requests. Check that it is healthy:

curl http://localhost:9901/v1/health
# {"status":"healthy","rdma_active":true,"drives_online":3,"drives_offline":0,"drives_total":3}

Configure the client on each GPU host

The MemKV client plugins read their settings from the YAML file that MEMKV_CONFIG names. Create one on each GPU host:

sudo mkdir -p /etc/memkv
sudo tee /etc/memkv/client.yaml > /dev/null <<EOF
servers:
  - server-0.memkv.example.com:9900
  - server-1.memkv.example.com:9900
rdma_devices: [mlx5_0, mlx5_1]
transport: auto       # auto picks RDMA when rdma_devices is set, TCP otherwise
auth_key: REPLACE_WITH_SERVERS_AUTH_KEY
license: /etc/memkv/minio.license
EOF
export MEMKV_CONFIG=/etc/memkv/client.yaml

Set auth_key to the key that memkv setup generated: copy the network.auth_key value from the server's /etc/memkv/config.yaml. Copy the license file to the GPU host as well.

Each setting in the file has a matching environment variable that overrides it, such as MEMKV_SERVERS, MEMKV_RDMA_DEVICES, MEMKV_LICENSE, and MEMKV_AUTH_KEY. See Configuration → Client for the full list and the order of precedence.

Next, connect your inference engine: vLLM, sglang, or Dynamo.

Run one MemKV server on the inference host, with file-mode storage and TCP. The same binary works on Linux and macOS.

Write the server configuration

Generate an auth key, save it, and write a configuration that uses one storage file:

sudo mkdir -p /etc/memkv /var/lib/memkv
openssl rand -hex 32 | sudo tee /etc/memkv/auth_key > /dev/null
sudo chmod 600 /etc/memkv/auth_key
AUTH=$(sudo cat /etc/memkv/auth_key)
sudo tee /etc/memkv/config.yaml > /dev/null <<EOF
network:
  address: 127.0.0.1:9900         # data plane; admin auto-binds at
                                  # port + 1 (9901)
  auth_key: "$AUTH"
memory:
  block_size: 2 MiB
  max_size: 1 GiB
storage:
  mode: file
  block_size: 4 MiB
  drives:
    - media: /var/lib/memkv/drive0.dat
      max_size: 16 GiB
EOF

The key is saved in /etc/memkv/auth_key so that the client step can read it from a new shell.

Start the server

Save the license file to /etc/memkv/minio.license, where the server finds it, and start the server:

sudo install -m 0600 /path/to/minio.license /etc/memkv/minio.license
sudo memkv start --config /etc/memkv/config.yaml

On the first start, the server allocates the whole storage file, so the first start is slower.

Check that it is healthy. Linux reports drive and RDMA fields; macOS returns the short form:

curl http://127.0.0.1:9901/v1/health
# macOS: {"status":"healthy"}
# Linux: {"status":"healthy","rdma_active":false,"drives_online":1,"drives_offline":0,"drives_total":1}

Point the inference client at the server

The MemKV client plugins and the LD_PRELOAD shim read their settings from MEMKV_CONFIG. Set transport: tcp so the client does not try RDMA. On macOS, tcp is already the default; on Linux the default is auto, which tries RDMA first.

AUTH=$(sudo cat /etc/memkv/auth_key)
cat > "$HOME/memkv-client.yaml" <<EOF
servers:
  - 127.0.0.1:9900
transport: tcp
auth_key: "$AUTH"
license: /etc/memkv/minio.license
EOF
export MEMKV_CONFIG="$HOME/memkv-client.yaml"

Any process that loads a MemKV plugin or the LD_PRELOAD shim now sends KV cache traffic to the local server over TCP.

The MemKV Helm chart deploys a StatefulSet with the quay.io/minio/memkv image. It runs one Pod per server, each on a different node.

Cluster requirements: Kubernetes 1.27 or later (1.34 or later for rdma.mode=dra), RDMA-capable NICs on each storage node, hugepages reserved on each node, and a license. The chart checks these when you install it.

Create persistent volumes for the NVMe drives

MemKV writes directly to raw block devices. By default (drives.mode: blockDevice), the chart claims one PersistentVolumeClaim (PVC) per drive per replica. Each claim binds to a local PersistentVolume (PV) that you create. The PV's nodeAffinity places the Pod on the host that owns the drive.

Download the example, edit it to match your nodes and drives, then apply it:

curl -fsSLO https://docs.min.io/memkv/charts/local-pv-example.yaml
kubectl apply -f local-pv-example.yaml

Create the license Secret

Request an Enterprise license at min.io/pricing, save it as minio.license, and load it into the cluster:

kubectl create namespace memkv
kubectl -n memkv create secret generic memkv-license \
    --from-file=license=/path/to/minio.license

Choose how Pods reach the RDMA NICs

Set rdma.mode to one of these values:

rdma.modeHow the Pod gets its NICsUse it when
hostNetwork (default)The Pod uses the node's network. Requires securityContext.privileged: true, the default.You want the simplest setup.
devicePluginThe RDMA shared device plugin adds the NICs. Set rdma.devicePlugin.resourceName to the resource it advertises.The plugin is already deployed in your cluster.
draA Dynamic Resource Allocation (DRA) network driver, such as DraNet, moves the NICs into the Pod. The Pod keeps its normal cluster network.You run Kubernetes 1.34 or later and want no host networking.

In devicePlugin mode the Pod also needs an address on the RDMA network, such as a macvlan attachment through Multus. Add the attachment's k8s.v1.cni.cncf.io/networks annotation through podAnnotations.

On a server with one NIC per rail, list every NIC in config.rdma.devices, for example [mlx5_0, mlx5_1]. Give each rail its own IP address on its own subnet. When devices is set, the chart ignores config.rdma.device.

For dra, create these before you install: a DeviceClass, which is cluster-scoped, and a ResourceClaimTemplate in the memkv namespace. A Pod gets only the NICs its claim requests, so request one device for each entry in config.rdma.devices. This template, for DraNet and a DeviceClass named rdma, requests two NICs:

apiVersion: resource.k8s.io/v1
kind: ResourceClaimTemplate
metadata:
  name: memkv-rdma
  namespace: memkv
spec:
  spec:
    devices:
      requests:
        - name: rails
          exactly:
            deviceClassName: rdma
            count: 2
            selectors:
              - cel:
                  expression: >-
                    device.attributes["dra.net"].rdma == true &&
                    device.attributes["dra.net"].state == "up" &&
                    has(device.attributes["dra.net"].ipv4)

DraNet does not offer the NIC that carries the node's default route. To give a Pod two rails, the node's management network must use a different NIC.

Install the chart

Set image.tag to the newest RELEASE tag at quay.io/minio/memkv.

Recommended. Each drive is a raw block PVC bound to a local PV, and each Pod runs on the host that owns its drives.

helm install memkv https://docs.min.io/memkv/charts/memkv.tgz \
    --namespace memkv \
    --set image.tag=RELEASE.2026-11-03T07-55-11Z \
    --set replicaCount=2 \
    --set drives.blockDevice.count=12 \
    --set drives.blockDevice.storageClass=memkv-local \
    --set license.existingSecret=memkv-license \
    --set config.memory.maxSize="64 GiB" \
    --set hugepages.amount=64Gi

Mounts the host's /dev into the Pod, and MemKV uses the /dev/nvmeXn1 paths directly.

In this mode the chart cannot place Pods on a specific node. Always set nodeSelector or affinity, so that MemKV does not start on a node without the configured drives.

helm install memkv https://docs.min.io/memkv/charts/memkv.tgz \
    --namespace memkv \
    --set image.tag=RELEASE.2026-11-03T07-55-11Z \
    --set drives.mode=hostDev \
    --set 'drives.hostDev.devices={/dev/nvme0n1,/dev/nvme1n1}' \
    --set 'nodeSelector.memkv\.minio\.io/storage=true' \
    --set license.existingSecret=memkv-license

Verify the deployment

kubectl -n memkv get pods -o wide
kubectl -n memkv get pvc -l app.kubernetes.io/instance=memkv

Each Pod should run on a different node, and every PVC should be Bound. Check the admin endpoint:

kubectl -n memkv port-forward svc/memkv-admin 9901:9901
curl http://127.0.0.1:9901/v1/health
# {"status":"healthy","rdma_active":true,"drives_online":12,"drives_offline":0,"drives_total":12}