A flexible storage plugin for Node-RED that supports multiple database backends including MongoDB, PostgreSQL, MySQL/MariaDB, and SQLite.
- Multi-database support: MongoDB, PostgreSQL, MySQL/MariaDB, SQLite
- Store all Node-RED data in your preferred database
- Separate collections/tables for each entity type
- Configurable collection/table names
- Support for Node-RED library entries
- Backward compatible with existing MongoDB configurations
- Extensible adapter registry - easily add custom database adapters
- Standardized configuration interface across all adapters
- Input validation and SQL injection protection
npm install node-red-contrib-db-storageMongoDB (included by default):
# MongoDB driver is includedPostgreSQL:
npm install pgMySQL/MariaDB:
npm install mysql2SQLite:
npm install better-sqlite3- Node.js >= 10.x
- Node-RED (embedded mode)
- One of the following databases:
- MongoDB >= 3.4
- PostgreSQL >= 9.6
- MySQL >= 5.7 or MariaDB >= 10.2
- SQLite 3
const settings = {
storageModule: require('node-red-contrib-db-storage'),
storageModuleOptions: {
type: 'mongodb',
url: 'mongodb://localhost:27017',
database: 'nodered'
}
};const settings = {
storageModule: require('node-red-contrib-db-storage'),
storageModuleOptions: {
type: 'postgres',
url: 'postgresql://user:password@localhost:5432/nodered'
}
};const settings = {
storageModule: require('node-red-contrib-db-storage'),
storageModuleOptions: {
type: 'mysql', // or 'mariadb'
url: 'mysql://user:password@localhost:3306/nodered'
}
};const settings = {
storageModule: require('node-red-contrib-db-storage'),
storageModuleOptions: {
type: 'sqlite',
url: '/path/to/nodered.db'
// or use ':memory:' for in-memory database
}
};This plugin requires running Node-RED in embedded mode. See the Node-RED embedding guide for details.
const http = require('http');
const express = require('express');
const RED = require('node-red');
const app = express();
const server = http.createServer(app);
const settings = {
httpAdminRoot: '/red',
httpNodeRoot: '/api',
userDir: './user',
// Storage Plugin Configuration
storageModule: require('node-red-contrib-db-storage'),
storageModuleOptions: {
type: 'mongodb', // or 'postgres', 'mysql', 'sqlite'
url: 'mongodb://localhost:27017',
database: 'nodered',
// Optional: custom collection/table names
collectionNames: {
flows: 'my-flows',
credentials: 'my-credentials',
settings: 'my-settings',
sessions: 'my-sessions'
}
}
};
RED.init(server, settings);
app.use(settings.httpAdminRoot, RED.httpAdmin);
app.use(settings.httpNodeRoot, RED.httpNode);
server.listen(8000, () => {
console.log('Node-RED server running on port 8000');
});
RED.start();| Option | Type | Required | Description |
|---|---|---|---|
type |
string | Yes* | Database type: 'mongodb', 'postgres', 'mysql', 'sqlite' |
url |
string | Yes | Database connection URL or file path |
database |
string | No** | Database name |
collectionNames |
object | No | Custom collection/table names |
*For backward compatibility, mongoUrl or postgresUrl can be used instead of type + url
**Database name is automatically extracted from the URL for PostgreSQL, MySQL, and SQLite. Required for MongoDB if not in URL.
// Old MongoDB configuration still works
storageModuleOptions: {
mongoUrl: 'mongodb://localhost:27017',
database: 'nodered'
}const settings = {
storageModule: require('node-red-contrib-db-storage'),
storageModuleOptions: {
type: process.env.DB_TYPE || 'mongodb',
url: process.env.DATABASE_URL || 'mongodb://localhost:27017',
database: process.env.DB_NAME || 'nodered'
}
};| Entity | Default Name |
|---|---|
| Flows | nodered-flows |
| Credentials | nodered-credentials |
| Settings | nodered-settings |
| Sessions | nodered-sessions |
The plugin implements the Node-RED storage module interface:
init(settings)- Initialize the storage modulegetFlows()/saveFlows(flows)- Manage flowsgetCredentials()/saveCredentials(credentials)- Manage credentialsgetSettings()/saveSettings(settings)- Manage settingsgetSessions()/saveSessions(sessions)- Manage sessionsgetLibraryEntry(type, path)/saveLibraryEntry(type, path, meta, body)- Manage library entriesclose()- Close database connection
You can create your own database adapter by extending the DatabaseAdapter class and registering it with the factory:
const { DatabaseAdapter, AdapterFactory } = require('node-red-contrib-db-storage/adapters');
class MyCustomAdapter extends DatabaseAdapter {
constructor(config) {
super(config);
// Initialize your adapter
// this.url and this.databaseName are set by parent class
}
async connect() {
// Connect to your database
}
async close() {
// Close connection
}
async findAll(collectionName) {
// Validate input (inherited from parent)
this.validateCollectionName(collectionName);
// Return all documents as array
}
async saveAll(collectionName, objects) {
this.validateCollectionName(collectionName);
this.validateObjectArray(objects);
// Save all objects (replace existing)
}
async findOneByPath(collectionName, path) {
this.validateCollectionName(collectionName);
this.validatePath(path);
// Find by path, return body or {}
}
async saveOrUpdateByPath(collectionName, path, meta, body) {
this.validateCollectionName(collectionName);
this.validatePath(path);
// Upsert by path
}
}
// Register the adapter with the factory
AdapterFactory.register(['mycustom', 'custom'], MyCustomAdapter);
// Now you can use it in configuration:
// { type: 'mycustom', url: '...', database: '...' }The AdapterFactory uses a registry pattern for extensibility:
const { AdapterFactory } = require('node-red-contrib-db-storage/adapters');
// Register a new adapter type
AdapterFactory.register('redis', RedisAdapter);
// Register with multiple aliases
AdapterFactory.register(['cockroachdb', 'crdb'], CockroachAdapter);
// Check if a type is registered
AdapterFactory.isRegistered('redis'); // true
// Get all supported types
AdapterFactory.getSupportedTypes(); // ['mongodb', 'postgres', 'mysql', 'sqlite', 'redis', ...]
// Unregister an adapter
AdapterFactory.unregister('redis');git clone https://github.com/srmurali002/node-red-contrib-db-storage.git
cd node-red-storage-plugin
npm installUnit Tests (with mocks, no database required):
npm test
# or
npm run test:unitIntegration Tests (require running databases):
# Start test databases
npm run docker:up
# Run all integration tests
npm run test:integration
# Run MongoDB integration tests only
npm run test:integration:mongo
# Run PostgreSQL integration tests only
npm run test:integration:postgres
# Run all tests (unit + integration)
npm run test:all
# Stop test databases
npm run docker:downEnvironment Variables for Integration Tests:
MONGO_URL=mongodb://localhost:27017
MONGO_DATABASE=nodered_test
POSTGRES_URL=postgresql://nodered:nodered@localhost:5432/nodered_test
TEST_DATABASES=mongodb,postgres # or just one
SKIP_INTEGRATION=true # skip integration testsnode-red-contrib-db-storage/
├── index.js # Main module
├── constants.js # Default configuration
├── adapters/
│ ├── index.js # Adapter exports
│ ├── DatabaseAdapter.js # Base adapter class
│ ├── AdapterFactory.js # Adapter factory with registry
│ ├── MongoAdapter.js # MongoDB implementation
│ ├── PostgresAdapter.js # PostgreSQL implementation
│ ├── MySQLAdapter.js # MySQL/MariaDB implementation
│ └── SQLiteAdapter.js # SQLite implementation
├── utils/
│ ├── index.js # Utility exports
│ └── UrlParser.js # URL parsing utilities
├── tests/
│ └── UrlParser.test.js # URL parser tests
├── examples/
│ └── node-red-app.js # Example application
└── package.json
Cause: The settings object passed to Node-RED is missing the storageModuleOptions property.
Solution: Ensure your settings include the required options:
const settings = {
storageModule: require('node-red-contrib-db-storage'),
storageModuleOptions: {
type: 'mongodb',
url: 'mongodb://localhost:27017',
database: 'nodered'
}
};Cause: No database URL was provided in the configuration.
Solution: Provide either:
urlwithtype(new format)mongoUrl(legacy MongoDB format)postgresUrl(legacy PostgreSQL format)
Cause: The database name could not be determined from the URL or configuration.
Solution: Either include the database name in the URL or add the database property:
storageModuleOptions: {
type: 'mongodb',
url: 'mongodb://localhost:27017/nodered', // Database in URL
// or
database: 'nodered' // Explicit database name
}Cause: The pg package is not installed but you're trying to use PostgreSQL.
Solution: Install the PostgreSQL driver:
npm install pgCause: The mysql2 package is not installed but you're trying to use MySQL/MariaDB.
Solution: Install the MySQL driver:
npm install mysql2Cause: The better-sqlite3 package is not installed but you're trying to use SQLite.
Solution: Install the SQLite driver:
npm install better-sqlite3Cause: Database server is not running or not accessible.
Solutions:
- Verify the database server is running
- Check the connection URL is correct
- Ensure network/firewall allows the connection
- For Docker, ensure the container is healthy:
docker ps docker logs <container-name>
Cause: Multiple Node-RED instances using the same database, or data being overwritten.
Solutions:
- Use unique collection names for each Node-RED instance
- Check that
saveFlows()is being called on deploy - Verify database connection is still active
Enable debug logging by setting the DEBUG environment variable:
DEBUG=* node your-app.js- Check MongoDB is running:
mongosh --eval "db.runCommand('ping')" - Verify connection string format:
mongodb://[user:pass@]host[:port]
- Check PostgreSQL is running:
pg_isready - Verify connection string format:
postgresql://user:pass@host:port/database - Ensure the database exists:
psql -l
- Check MySQL is running:
mysqladmin ping - Verify connection string format:
mysql://user:pass@host:port/database - Ensure user has necessary permissions:
GRANT ALL PRIVILEGES ON database.* TO 'user'@'host'
- Ensure the directory for the database file exists
- Check file permissions for the target path
- For in-memory databases, use
:memory:as the URL
If you're still experiencing issues:
- Check existing issues
- Create a new issue with:
- Node.js version
- Node-RED version
- Database type and version
- Full error message and stack trace
- Configuration (without sensitive data)
- Added MySQL/MariaDB adapter
- Added SQLite adapter
- New: Adapter registry pattern for extensibility (Open/Closed Principle)
- New: URL parsing utility for automatic database name extraction
- New: Input validation to prevent SQL injection
- Refactored to encapsulate module state
- Standardized configuration interface across all adapters
- Comprehensive test coverage (136 tests)
- Breaking: Restructured to support multiple databases
- Added PostgreSQL adapter
- Added database adapter abstraction layer
- Added AdapterFactory for creating adapters
- Backward compatible with existing MongoDB configurations
- Improved error handling and validation
- Comprehensive test suite
- Fixed critical bugs in MongoDB operations
- Added unit tests
- Added configurable collection names
- Integration tests
- MySQL/MariaDB adapter
- SQLite adapter
- Adapter registry pattern
- Input validation and security
- Redis adapter
- Connection pooling configuration
- Retry logic for connection failures
- TypeScript definitions
- Migration utilities between databases
- Per-data-type adapter configuration (e.g., Redis for sessions, PostgreSQL for flows)
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Create a new adapter file in
adapters/extendingDatabaseAdapter - Register it with
AdapterFactory.register()inAdapterFactory.js - Export it from
adapters/index.js - Add unit tests in
adapters/YourAdapter.test.js - Add integration tests in
adapters/YourAdapter.integration.test.js - Update documentation in README.md
MIT License - see the LICENSE file for details.
Multi-database support and continued development by Muralidhar Reddy Challa.
If you encounter any issues or have questions, please open an issue.