Event-Driven CQRS Architecture on High-Throughput VPS Nodes with NATS JetStream
Scale read/write decoupled microservices using NATS JetStream persistent log streams, avoiding Kafka cluster management overhead on dedicated cloud servers.
Netbay Engineering
Netbay Engineering
On this page
Command Query Responsibility Segregation (CQRS) and Event Sourcing are powerful patterns for high-throughput cloud applications where read demands vastly exceed write volume. However, traditional implementations often mandate massive Apache Kafka or ZooKeeper clusters, requiring heavy JVM memory allocations and operational complexity.
In 2026, modern cloud teams are turning to NATS JetStream. Written in Go, NATS JetStream embeds a battle-tested Raft consensus engine capable of processing millions of messages per second on a single lightweight VPS while consuming under 50 MB of memory.
Decoupling the Write and Read Paths
In a high-performance CQRS system:
- Command Side (Writes): Incoming HTTP POST/PUT requests are validated, written to a primary transactional database (like PostgreSQL), and immediately emitted as persistent events to NATS JetStream.
- Event Log (Streaming): JetStream persists events to an append-only file storage backed by NVMe SSD, guaranteeing at-least-once delivery.
- Query Side (Reads): Projection workers subscribe to the event stream, asynchronously updating denormalized read replicas (such as Redis or SQLite) optimized for sub-millisecond retrieval.
Configuring the JetStream Stream Definition
NATS JetStream streams are configured with storage limits, retention policies, and replication factors:
# Define a high-throughput durable stream for order lifecycle events
nats stream add ORDERS --subjects "orders.*" --storage file --retention limits --max-bytes 10GB --max-age 7d --discard old --dupe-window 2mOn disk, JetStream writes blocks directly to NVMe storage with linear sequential I/O, allowing standard VPS hardware to easily hit 80,000 published messages per second.
Event Consumer in TypeScript
Here is a resilient projection worker listening to the stream and updating a denormalized query cache:
import { connect, JSONCodec } from 'nats';
interface OrderCreatedEvent {
orderId: string;
customerEmail: string;
amountCents: number;
timestamp: string;
}
async function startProjectionWorker() {
const nc = await connect({ servers: 'nats://127.0.0.1:4222' });
const js = nc.jetstream();
const jc = JSONCodec<OrderCreatedEvent>();
// Create or bind to durable consumer
const consumer = await js.consumers.get('ORDERS', 'projection-builder');
const messages = await consumer.consume();
console.log('Worker listening for JetStream events...');
for await (const m of messages) {
try {
const event = jc.decode(m.data);
// Update read model in Redis or SQLite
console.log('Projecting order to read cache:', event.orderId);
m.ack();
} catch (err) {
console.error('Error processing event:', err);
m.nak(); // Re-queue for delivery
}
}
}
startProjectionWorker();Video Deep Dive on Microservices & CQRS
Learn more about decoupling command paths and event architecture principles:
Replacing heavyweight streaming platforms with NATS JetStream allows lean engineering teams to operate high-throughput CQRS architectures reliably on straightforward cloud nodes.
Experience low-latency NVMe disk performance and dedicated CPU threads on Netbay Cloud VPS instances at netbayhosts.in.
Keep reading
Follow along on a real VPS
Deploy Linux in under 60 seconds
These guides are written against Ubuntu, Debian, and RHEL-family images — the same ones on NetBay.
Deploy an instance