SQLite-based graph database with Cypher query support
npm install nicefox-graphdb

A lightweight graph database with Cypher query support, powered by SQLite.
``bash`
npm install nicefox-graphdb
The better-sqlite3 native module is an optional dependency:
- Production mode (remote HTTP client): No native dependencies, no compilation required
- Development mode (local SQLite): Requires better-sqlite3
If you only connect to a remote GraphDB server, you can skip native compilation entirely:
`bash`
npm install nicefox-graphdb --ignore-optional
For local/embedded mode, ensure better-sqlite3 is installed:
`bash`
npm install nicefox-graphdb better-sqlite3
`typescript
import { GraphDB } from 'nicefox-graphdb';
const db = await GraphDB({
project: 'myapp', // or process.env.GRAPHDB_PROJECT
apiKey: 'nfx_xxx', // or process.env.GRAPHDB_API_KEY
});
// Create nodes and relationships
await db.execute(
CREATE (alice:User {name: 'Alice'})-[:FOLLOWS]->(bob:User {name: 'Bob'}));
// Query the graph
const users = await db.query('MATCH (u:User) RETURN u.name AS name');
console.log(users); // [{ name: 'Alice' }, { name: 'Bob' }]
db.close();
`
NiceFox GraphDB automatically adapts based on the NODE_ENV environment variable:
| Mode | NODE_ENV | Behavior |development
|------|-----------|----------|
| Development | | Uses local SQLite database. url and apiKey are ignored. |production
| Production | (or unset) | Connects to remote server via HTTP. url and apiKey are required. |
This means you can use the exact same code in both environments:
`typescript`
// Works in both development and production!
const db = await GraphDB({ project: 'myapp' });
When NODE_ENV=development:url
- A local SQLite database is created automatically
- No server setup required
- and apiKey parameters are ignored./data/{env}/{project}.db
- Data persists at by default
`bash`Run your app in development mode
NODE_ENV=development node app.js
When NODE_ENV=production (or unset):url
- Connects to a remote GraphDB server via HTTP
- and apiKey are required
`bash`Run your app in production mode
NODE_ENV=production GRAPHDB_API_KEY=xxx node app.js
| Option | Type | Required | Default | Description |
|--------|------|----------|---------|-------------|
| url | string | No | GRAPHDB_URL or https://graphdb.nicefox.net | Base URL of the GraphDB server (production only) |project
| | string | Yes | GRAPHDB_PROJECT | Project name |apiKey
| | string | No | GRAPHDB_API_KEY | API key for authentication (production only) |env
| | string | No | NODE_ENV or production | Environment (determines database isolation) |dataPath
| | string | No | GRAPHDB_DATA_PATH or ./data | Path for local data storage (development only). Use ':memory:' for in-memory database |
Production (default when NODE_ENV is unset or production):`typescript`
const db = await GraphDB({
project: 'myapp', // or process.env.GRAPHDB_PROJECT
apiKey: 'nfx_xxx', // or process.env.GRAPHDB_API_KEY
url: 'https://my-server', // or process.env.GRAPHDB_URL (default: graphdb.nicefox.net)
});
Development (when NODE_ENV=development):`typescript`
const db = await GraphDB({
project: 'myapp', // or process.env.GRAPHDB_PROJECT
dataPath: './local-data', // or process.env.GRAPHDB_DATA_PATH (default: ./data)
});
// url and apiKey are ignored - uses local SQLite
Testing (when NODE_ENV=development):`typescript`
const db = await GraphDB({
project: 'test-project',
dataPath: ':memory:', // in-memory database, resets on each run
});
Create a new GraphDB client. Returns a promise that resolves to a client instance.
Execute a Cypher query and return results as an array.
`typescript`
const users = await db.query<{ name: string; age: number }>(
'MATCH (u:User) WHERE u.age > $minAge RETURN u.name AS name, u.age AS age',
{ minAge: 21 }
);
// users = [{ name: 'Alice', age: 25 }, { name: 'Bob', age: 30 }]
Execute a mutating query (CREATE, SET, DELETE, MERGE) without expecting return data.
`typescript`
await db.execute('CREATE (n:User {name: $name, email: $email})', {
name: 'Alice',
email: 'alice@example.com'
});
Execute a query and return the full response including metadata.
`typescript`
const response = await db.queryRaw('MATCH (n) RETURN n LIMIT 10');
console.log(response.meta.count); // Number of rows
console.log(response.meta.time_ms); // Query execution time in ms
console.log(response.data); // Array of results
Create a node and return its ID.
`typescript`
const userId = await db.createNode('User', { name: 'Alice', email: 'alice@example.com' });
Find a node by label and properties.
`typescript`
const user = await db.getNode('User', { email: 'alice@example.com' });
if (user) {
console.log(user.name); // 'Alice'
}
Update properties on a node.
`typescript`
await db.updateNode(userId, { name: 'Alice Smith', verified: true });
Delete a node and all its relationships (DETACH DELETE).
`typescript`
await db.deleteNode(userId);
Create a relationship between two nodes.
`typescript`
await db.createEdge(aliceId, 'FOLLOWS', bobId, { since: '2024-01-01' });
Check server health. In development mode, always returns { status: 'ok', ... }.
Close the client and release resources. Always call this when done.
`typescript`
const db = await GraphDB({ ... });
try {
// ... use db
} finally {
db.close();
}
| Clause | Example |
|--------|---------|
| CREATE | CREATE (n:User {name: 'Alice'}) |MATCH
| | MATCH (n:User) RETURN n |OPTIONAL MATCH
| | OPTIONAL MATCH (n)-[:KNOWS]->(m) RETURN m |MERGE
| | MERGE (n:User {email: $email}) |WHERE
| | WHERE n.age > 21 AND n.active = true |SET
| | SET n.name = 'Bob', n.updated = true |DELETE
| | DELETE n |DETACH DELETE
| | DETACH DELETE n |RETURN
| | RETURN n.name AS name, count(*) AS total |WITH
| | WITH n, count(*) AS cnt WHERE cnt > 1 |UNWIND
| | UNWIND $list AS item CREATE (n {value: item}) |UNION / UNION ALL
| | MATCH (n:A) RETURN n UNION MATCH (m:B) RETURN m |ORDER BY
| | ORDER BY n.name DESC |SKIP / LIMIT
| | SKIP 10 LIMIT 5 |DISTINCT
| | RETURN DISTINCT n.category |CASE/WHEN
| | RETURN CASE WHEN n.age > 18 THEN 'adult' ELSE 'minor' END |CALL
| | CALL db.labels() YIELD label RETURN label |
| Category | Operators |
|----------|-----------|
| Comparison | =, <>, <, >, <=, >= |AND
| Logical | , OR, NOT |CONTAINS
| String | , STARTS WITH, ENDS WITH |IN
| List | |IS NULL
| Null | , IS NOT NULL |EXISTS
| Pattern | |+
| Arithmetic | , -, *, /, % |
Aggregation: COUNT, SUM, AVG, MIN, MAX, COLLECT
Scalar: ID, coalesce
String: toUpper, toLower, trim, substring, replace, toString, split
List: size, head, last, tail, keys, range
Node/Relationship: labels, type, properties
Math: abs, ceil, floor, round, rand, sqrt
Date/Time: date, datetime, timestamp
`cypher`
-- Find friends of friends (1 to 3 hops)
MATCH (a:User {name: 'Alice'})-[:KNOWS*1..3]->(b:User)
RETURN DISTINCT b.name
`cypher
-- List all labels
CALL db.labels() YIELD label RETURN label
-- List all relationship types
CALL db.relationshipTypes() YIELD type RETURN type
-- List all property keys
CALL db.propertyKeys() YIELD key RETURN key
`
For production deployments, run a dedicated server:
`bashStart the server
npx nicefox-graphdb serve --port 3000 --data ./data
$3
`bash
Create a new project (generates API key)
npx nicefox-graphdb create myapp --data ./dataOutput:
[created] production/myapp.db
API Key: nfx_abc123...
`$3
`bash
Server
nicefox-graphdb serve [options]
-p, --port Port to listen on (default: 3000)
-d, --data Data directory (default: /var/data/nicefox-graphdb)
-H, --host Host to bind to (default: localhost)
-b, --backup Backup directory (enables backup endpoints)Project management
nicefox-graphdb create Create new project with API keys
nicefox-graphdb delete Delete project (use --force)
nicefox-graphdb list List all projectsEnvironment management
nicefox-graphdb clone --from --to Copy between environments
nicefox-graphdb wipe --env Clear environment databaseDirect queries
nicefox-graphdb query "CYPHER"Backup
nicefox-graphdb backup [options]
-o, --output Backup directory
-p, --project Backup specific project
--status Show backup statusAPI keys
nicefox-graphdb apikey add
nicefox-graphdb apikey list
nicefox-graphdb apikey remove
`Why NiceFox?
| Feature | NiceFox GraphDB | Neo4j |
|---------|-----------------|-------|
| Deployment | Single package, zero config | Complex setup, JVM required |
| Development | Local SQLite, no server needed | Server required |
| Backup | Just copy the SQLite file | Enterprise license required |
| Resource usage | ~50MB RAM | 1GB+ RAM minimum |
| Cypher support | Core subset | Full |
| Cost | Free, MIT license | Free tier limited |
NiceFox is ideal for:
- Applications needing graph queries without ops burden
- Projects that outgrow JSON but don't need a full graph database
- Self-hosted deployments where simplicity matters
- Development and testing with instant local databases
Advanced Usage
$3
For advanced use cases, you can access the underlying components:
`typescript
import { GraphDatabase, Executor, parse, translate } from 'nicefox-graphdb';// Direct database access
const db = new GraphDatabase('./my-database.db');
db.initialize();
const executor = new Executor(db);
const result = executor.execute('MATCH (n) RETURN n LIMIT 10');
db.close();
// Parse Cypher to AST
const parseResult = parse('MATCH (n:User) RETURN n');
if (parseResult.success) {
console.log(parseResult.query);
}
// Translate AST to SQL
const translation = translate(parseResult.query, {});
console.log(translation.statements);
`$3
`typescript
import { createServer } from 'nicefox-graphdb';
import { serve } from '@hono/node-server';const { app, dbManager } = createServer({
dataPath: './data',
apiKeys: {
'my-api-key': { project: 'myapp', env: 'production' }
}
});
serve({ fetch: app.fetch, port: 3000 });
``MIT - Conrad Lelubre