DataStax Official Driver

Node.js Driver

Build modern JavaScript/TypeScript applications with Cassandra!

🟢 DataStax Node.js Driver for Apache Cassandra

Official driver with modern JavaScript features - Promise-based, TypeScript support, and production-ready!

Why Use the Node.js Driver?

  • 🚀 Promise-based API: Clean async/await syntax
  • 📘 TypeScript Support: Full type definitions included
  • ⚡ High Performance: Connection pooling, prepared statements
  • 🔄 Automatic Failover: Built-in retry policies
  • 📊 Load Balancing: Smart request distribution
  • 🛡️ Production Ready: Battle-tested in production

Latest Version: 4.x

Supports Cassandra 2.1+ and DataStax Enterprise 4.7+

Actively maintained by DataStax with regular updates and bug fixes.

📦 Installation & Setup

1

Install the Driver

# NPM $ npm install cassandra-driver # Yarn $ yarn add cassandra-driver # With TypeScript types (already included!) $ npm install --save-dev @types/cassandra-driver
2

Create Project Structure

# Create project $ mkdir my-cassandra-app $ cd my-cassandra-app $ npm init -y # Install driver $ npm install cassandra-driver # Create main file $ touch index.js
3

Verify Installation

// index.js const cassandra = require('cassandra-driver'); console.log('Driver version:', cassandra.version); // Output: Driver version: 4.7.2 ✅

🔌 Connecting to Cassandra

Basic Connection

const cassandra = require('cassandra-driver'); // Create client const client = new cassandra.Client({ contactPoints: ['127.0.0.1'], localDataCenter: 'datacenter1', keyspace: 'myapp' }); // Connect async function connect() { await client.connect(); console.log('Connected to Cassandra!'); } connect();

Production Configuration

const cassandra = require('cassandra-driver'); const client = new cassandra.Client({ // Cluster nodes contactPoints: [ '10.0.0.1', '10.0.0.2', '10.0.0.3' ], // Data center (REQUIRED) localDataCenter: 'DC1', // Keyspace keyspace: 'production', // Authentication credentials: { username: 'cassandra', password: 'your_password' }, // Connection pooling pooling: { coreConnectionsPerHost: { [cassandra.types.distance.local]: 2, [cassandra.types.distance.remote]: 1 } }, // Query options queryOptions: { consistency: cassandra.types.consistencies.localQuorum } }); // Error handling client.on('error', (err) => { console.error('Client error:', err); }); await client.connect();

localDataCenter is REQUIRED!

Starting with driver 4.x, you MUST specify localDataCenter.

Run nodetool status on your cluster to find the DC name.

📝 CRUD Operations

CREATE - Insert Data

// Insert user const query = 'INSERT INTO users (id, name, email) VALUES (?, ?, ?)'; const params = ['uuid-123', 'Alice', 'alice@example.com']; await client.execute(query, params, { prepare: true }); console.log('User inserted!'); // Insert with TTL const queryTTL = 'INSERT INTO sessions (id, data) VALUES (?, ?) USING TTL ?'; await client.execute(queryTTL, ['session-1', 'data', 3600], { prepare: true });

READ - Query Data

// Select single user const query = 'SELECT * FROM users WHERE id = ?'; const result = await client.execute(query, ['uuid-123'], { prepare: true }); if (result.rowLength > 0) { const user = result.rows[0]; console.log('User:', user.name, user.email); } // Select multiple users const allUsers = await client.execute('SELECT * FROM users'); allUsers.rows.forEach(user => { console.log(user.name); });

UPDATE - Modify Data

// Update user const query = 'UPDATE users SET email = ? WHERE id = ?'; await client.execute(query, ['newemail@example.com', 'uuid-123'], { prepare: true }); // Update with conditions const updateQuery = 'UPDATE users SET login_count = login_count + 1 WHERE id = ?'; await client.execute(updateQuery, ['uuid-123'], { prepare: true });

DELETE - Remove Data

// Delete user const query = 'DELETE FROM users WHERE id = ?'; await client.execute(query, ['uuid-123'], { prepare: true }); // Delete specific columns const deleteEmail = 'DELETE email FROM users WHERE id = ?'; await client.execute(deleteEmail, ['uuid-123'], { prepare: true });

⚡ Prepared Statements

Use prepared statements for better performance and security!

// BAD: Simple query (parsed every time) await client.execute('SELECT * FROM users WHERE id = ?', [userId]); // GOOD: Prepared statement (parsed once) await client.execute( 'SELECT * FROM users WHERE id = ?', [userId], { prepare: true } ← Use this! ); // BEST: Reuse prepared statement const query = 'INSERT INTO users (id, name) VALUES (?, ?)'; for (let i = 0; i < 1000; i++) { await client.execute(query, [i, `User ${i}`], { prepare: true }); } // Query prepared once, reused 1000 times! ✅

Performance Boost!

Prepared statements are 3-5x faster!

  • Query parsed once on server
  • Binary protocol (smaller packets)
  • Protection against CQL injection

🔄 Async/Await Patterns

Basic Async/Await

async function getUser(userId) { try { const result = await client.execute( 'SELECT * FROM users WHERE id = ?', [userId], { prepare: true } ); if (result.rowLength === 0) { return null; } return result.rows[0]; } catch (err) { console.error('Error:', err); throw err; } } // Usage const user = await getUser('uuid-123'); console.log(user.name);

Parallel Queries

// Execute multiple queries in parallel async function getUserProfile(userId) { const [user, posts, friends] = await Promise.all([ client.execute('SELECT * FROM users WHERE id = ?', [userId], { prepare: true }), client.execute('SELECT * FROM posts WHERE user_id = ?', [userId], { prepare: true }), client.execute('SELECT * FROM friends WHERE user_id = ?', [userId], { prepare: true }) ]); return { user: user.rows[0], posts: posts.rows, friends: friends.rows }; }

Batch Operations

// Batch insert const queries = [ { query: 'INSERT INTO users (id, name) VALUES (?, ?)', params: ['1', 'Alice'] }, { query: 'INSERT INTO users (id, name) VALUES (?, ?)', params: ['2', 'Bob'] }, { query: 'INSERT INTO users (id, name) VALUES (?, ?)', params: ['3', 'Charlie'] } ]; await client.batch(queries, { prepare: true }); console.log('Batch executed!');

🚀 Advanced Features

🔄

Stream API

Process large result sets efficiently

const query = 'SELECT * FROM users'; client.stream(query) .on('readable', function() { let row; while (row = this.read()) { console.log(row.name); } }) .on('end', () => { console.log('Done!'); });
⚡

Retry Policies

Automatic retry on failures

const client = new cassandra.Client({ contactPoints: ['127.0.0.1'], localDataCenter: 'DC1', policies: { retry: new cassandra .policies.retry .RetryPolicy() } });
🎯

Load Balancing

Smart request distribution

const client = new cassandra.Client({ contactPoints: ['127.0.0.1'], localDataCenter: 'DC1', policies: { loadBalancing: new cassandra .policies.loadBalancing .DCAwareRoundRobinPolicy() } });
🔒

SSL/TLS

Encrypted connections

const fs = require('fs'); const client = new cassandra.Client({ contactPoints: ['127.0.0.1'], localDataCenter: 'DC1', sslOptions: { ca: [fs.readFileSync('ca.pem')] } });

💡 Best Practices

Connection Management

  • ✅ Reuse client: Create ONE client for entire app
  • ✅ Connection pool: Driver manages connections automatically
  • ❌ Don't create per-request: Expensive and unnecessary
  • ✅ Graceful shutdown: Call client.shutdown() on exit

Query Optimization

  • ✅ Always use prepared statements: { prepare: true }
  • ✅ Use appropriate consistency: Don't always use QUORUM
  • ✅ Avoid SELECT *: Query only needed columns
  • ✅ Use LIMIT: Prevent large result sets
  • ✅ Batch wisely: Only for same partition key

Common Mistakes

  • ❌ Creating client per request → Reuse one client
  • ❌ Not using prepared statements → Always use prepare: true
  • ❌ Missing localDataCenter → Required in driver 4.x
  • ❌ Blocking event loop → Use async/await properly
  • ❌ No error handling → Always use try/catch

Complete Example

// app.js - Production-ready setup const cassandra = require('cassandra-driver'); // Create client (ONCE for entire app) const client = new cassandra.Client({ contactPoints: ['10.0.0.1', '10.0.0.2'], localDataCenter: 'DC1', keyspace: 'myapp', credentials: { username: process.env.CASSANDRA_USER, password: process.env.CASSANDRA_PASSWORD }, queryOptions: { consistency: cassandra.types.consistencies.localQuorum } }); // Connect on startup async function init() { try { await client.connect(); console.log('Connected to Cassandra!'); } catch (err) { console.error('Connection failed:', err); process.exit(1); } } // User operations class UserRepository { async create(id, name, email) { const query = 'INSERT INTO users (id, name, email) VALUES (?, ?, ?)'; await client.execute(query, [id, name, email], { prepare: true }); } async findById(id) { const query = 'SELECT * FROM users WHERE id = ?'; const result = await client.execute(query, [id], { prepare: true }); return result.rowLength > 0 ? result.rows[0] : null; } async update(id, email) { const query = 'UPDATE users SET email = ? WHERE id = ?'; await client.execute(query, [email, id], { prepare: true }); } async delete(id) { const query = 'DELETE FROM users WHERE id = ?'; await client.execute(query, [id], { prepare: true }); } } // Graceful shutdown process.on('SIGTERM', async () => { await client.shutdown(); process.exit(0); }); // Export module.exports = { client, UserRepository };

🎉 You're Ready to Build with Node.js!

You now know how to use the Node.js driver for Cassandra!

🚀 Quick Start Checklist:

  1. ✅ Install: npm install cassandra-driver
  2. ✅ Create client with localDataCenter
  3. ✅ Always use { prepare: true }
  4. ✅ Use async/await for clean code
  5. ✅ Implement proper error handling
  6. ✅ Reuse ONE client for entire app
  7. ✅ Graceful shutdown on exit

💡 Key Takeaways:

  • 🟢 Modern API: Promise-based with async/await
  • 📘 TypeScript: Full type definitions included
  • ⚡ Performance: Prepared statements are 3-5x faster
  • 🔄 Automatic: Retry, failover, load balancing built-in
  • 🛡️ Production Ready: Battle-tested at scale

🟢 Build amazing apps with Node.js + Cassandra! 🚀

Advertisement

📱 Responsive Ad 📱