← Back

NVMe SSDs

4 min read

NVMe SSDs in the cloud are high-speed solid-state drives that are physically attached directly to the underlying host server — unlike network-attached storage such as AWS EBS or GCP Persistent Disk, they sit on the same physical box as your compute.


What NVMe SSDs Are


What They Are Used For by Cloud Providers & Databases

In cloud-native architectures (such as Turbopuffer), local NVMe SSDs serve as a high-speed warm caching tier positioned between cold object storage (S3/GCS) and DRAM:


Writing and Reading

On AWS EC2 instances with local NVMe SSD instance storage (such as i3, i4i, c5ad, m6i, r6id), the NVMe drives are physically attached directly to the host server hypervisor and mounted as local POSIX directories on the Linux operating system (e.g., /mnt/nvme0, /mnt/ephemeral0, or /data).

Because the NVMe SSD is a direct local block device on the instance, you do not use the AWS SDK (@aws-sdk/client-s3). Instead, reading and writing in TypeScript is done using native Node.js filesystem APIs (node:fs/promises or node:fs) — the full picture of how both memory tiers are accessed and billed is in Accessing DRAM & NVMe SSDs in the Cloud.

TypeScript NVMe Block Read/Write Example

This example demonstrates how to:

  1. Initialize a pre-allocated binary buffer file on the mounted NVMe path.
  2. Perform positional offset writes (pwrite) and positional offset reads (pread) for fixed block sizes (e.g. 128 KB chunks).
  3. Issue parallel concurrent reads (Promise.all) to saturate the NVMe drive's hardware queue depth.
typescript
import { open, mkdir } from "node:fs/promises";
import { join } from "node:path";
 
// AWS EC2 NVMe Instance Store drives are mounted
// as local filesystem directories
const NVME_MOUNT_PATH = process.env.NVME_PATH || "/mnt/nvme0";
 
export interface BlockWriteResult {
  offset: number;
  bytesWritten: number;
}
 
export class NvmeBlockStorage {
  private filePath: string;
 
  constructor(filename: string = "cache-ring-buffer.bin") {
    this.filePath = join(NVME_MOUNT_PATH, filename);
  }
 
  /**
   * Initializes the NVMe directory and creates a
   * pre-allocated file. Pre-allocating prevents OS
   * filesystem allocation stalls during heavy writes.
   */
  async init(preallocateSizeBytes: number = 100 * 1024 * 1024) {
    // 1. Ensure the local NVMe mount directory exists
    await mkdir(NVME_MOUNT_PATH, { recursive: true });
 
    // 2. Open or create the file on the local NVMe SSD
    const handle = await open(this.filePath, "a+");
    try {
      await handle.truncate(preallocateSizeBytes);
      console.log(
        `[NVMe] Initialized file at ${this.filePath} ` +
          `(${(preallocateSizeBytes / (1024 * 1024)).toFixed(2)} MB)`,
      );
    } finally {
      await handle.close();
    }
  }
 
  /**
   * Writes a binary block (e.g. 128 KB) directly to
   * a specific byte offset on the NVMe SSD.
   */
  async writeBlock(
    offset: number,
    data: Buffer,
  ): Promise<BlockWriteResult> {
    const handle = await open(this.filePath, "r+");
    try {
      // Positional write (pwrite) at specific byte offset
      const { bytesWritten } = await handle.write(
        data,
        0,
        data.length,
        offset,
      );
      return { offset, bytesWritten };
    } finally {
      await handle.close();
    }
  }
 
  /**
   * Reads a specific byte slice directly from the
   * NVMe SSD without loading the whole file.
   */
  async readBlock(offset: number, length: number): Promise<Buffer> {
    const handle = await open(this.filePath, "r");
    const buffer = Buffer.allocUnsafe(length);
    try {
      // Positional read (pread) at specific byte offset
      await handle.read(buffer, 0, length, offset);
      return buffer;
    } finally {
      await handle.close();
    }
  }
 
  /**
   * Executes concurrent reads across multiple offsets
   * to saturate NVMe drive queue depth.
   */
  async batchReadParallel(
    offsets: number[],
    blockLength: number,
  ): Promise<Buffer[]> {
    const readPromises = offsets.map((off) =>
      this.readBlock(off, blockLength),
    );
    return Promise.all(readPromises);
  }
}
 
// --- Usage Example ---
 
async function main() {
  const nvme = new NvmeBlockStorage("vector-cache.bin");
  const BLOCK_SIZE = 128 * 1024; // 128 KB Block
 
  // 1. Pre-allocate 50 MB on the NVMe drive
  await nvme.init(50 * 1024 * 1024);
 
  // 2. Prepare sample 128 KB binary payload
  const samplePayload = Buffer.alloc(BLOCK_SIZE, "A");
 
  // 3. Write 128 KB blocks at distinct offsets
  await nvme.writeBlock(0, samplePayload);
  await nvme.writeBlock(BLOCK_SIZE, samplePayload);
 
  // 4. Issue parallel reads to leverage NVMe I/O depth
  const offsetsToRead = [0, BLOCK_SIZE];
  const startTime = performance.now();
 
  const blocks = await nvme.batchReadParallel(offsetsToRead, BLOCK_SIZE);
 
  const duration = performance.now() - startTime;
  console.log(
    `[NVMe] Read ${blocks.length} blocks ` +
      `(${(blocks.length * BLOCK_SIZE) / 1024} KB) ` +
      `in ${duration.toFixed(2)} ms`,
  );
}
 
main().catch(console.error);

Key Execution Details

  1. Linux Formatting & Mount Point: Before running Node.js code on EC2, the ephemeral NVMe block device must be formatted and mounted (e.g. sudo mkfs.xfs /dev/nvme1n1 && sudo mount /dev/nvme1n1 /mnt/nvme0).
  2. High Parallelism: Calling Promise.all() across dozens of async reads fires concurrent POSIX file read requests down to the Linux kernel, filling the NVMe SSD's internal hardware queues to maximize throughput.
  3. Data Loss Warning: AWS EC2 Instance Store NVMe SSDs are ephemeral — if the EC2 instance is stopped or terminated, all local SSD data is erased. Use S3 as the durable master source of truth and the NVMe SSD purely as a fast local cache.


When NVMe SKUs Arrived in the Cloud