Status: Beta - API is stable and tested. Published as datahike@next on npm.
The Datahike JavaScript API provides a Promise-based interface for Node.js and browser environments. All async operations return Promises, and data is automatically converted between JavaScript and ClojureScript.
src/datahike/js/
├── api.cljs # Main JS API implementation
├── api_macros.clj # Macro for generating API functions
├── naming.cljc # Shared naming conventions (ClojureScript → JavaScript)
└── typescript.clj # TypeScript definition generator
npm-package/
├── test.js # Comprehensive test suite
├── package.template.json # Version-controlled template
├── README.md # npm package documentation
├── PUBLISHING.md # Publishing guide
└── index.d.ts # Generated TypeScript definitions
bb/src/tools/
└── npm.clj # Build automation (version, types, compile, test)
The JS API uses a modern automated build pipeline:
# Full build: version + types + compile + test
bb npm-build
# Individual steps:
bb npm-version # Generate package.json from template with version from config.edn
bb npm-types # Generate TypeScript definitions
bb npm-test # Run npm package tests
Versions are automatically calculated as major.minor.commit-count from config.edn.
Output is generated in npm-package/datahike.js.api.js with advanced compilation.
npm install datahike
const d = require('datahike');
const crypto = require('crypto');
async function example() {
// Configuration - must use UUID for :id
const config = {
store: {
backend: ':memory',
id: crypto.randomUUID()
}
};
// Create database
await d.createDatabase(config);
// Connect
const conn = await d.connect(config);
// Define schema
// Keys: WITHOUT colon (plain strings)
// Values: WITH colon prefix (keywords)
const schema = [
{
'db/ident': ':name',
'db/valueType': ':db.type/string',
'db/cardinality': ':db.cardinality/one'
},
{
'db/ident': ':age',
'db/valueType': ':db.type/long',
'db/cardinality': ':db.cardinality/one'
}
];
await d.transact(conn, schema);
// Insert data (data keys without colons)
const data = [
{ name: 'Alice', age: 30 },
{ name: 'Bob', age: 25 }
];
await d.transact(conn, data);
// Get database value (synchronous)
const db = await d.db(conn);
// Get datoms
const datoms = await d.datoms(db, ':eavt');
console.log('Datoms:', datoms.length);
// Pull API (pattern attributes with colons)
const entityId = 1; // Find ID through query or datoms
const pulled = await d.pull(db, [':name', ':age'], entityId);
console.log('Entity:', pulled);
// Clean up
d.release(conn);
await d.deleteDatabase(config);
}
: → keywords (for values only): prefix:)⚠️ Note: The JavaScript keyword syntax translation may change in future versions to simplify the API.
Current syntax (critical distinction):
: prefix: prefix (keywords): prefix: prefix (keywords)// ✅ Correct
const schema = [{
'db/ident': ':name', // Key: no colon, Value: with colon
'db/valueType': ':db.type/string' // Key: no colon, Value: with colon
}];
const data = [
{ name: 'Alice', age: 30 } // Data keys: no colons
];
const pattern = [':name', ':age']; // Pattern: with colons
// ❌ Wrong
const schema = [{
':db/ident': ':name', // Bad - key has colon
'db/valueType': 'db.type/string' // Bad - value missing colon
}];
const crypto = require('crypto');
// In-memory backend (requires UUID)
const memConfig = {
store: {
backend: ':memory',
id: crypto.randomUUID()
}
};
// File backend (Node.js only)
const fileConfig = {
store: {
backend: ':file',
path: '/path/to/db'
}
};
All database operations return Promises. Use await or .then():
// Using await (recommended)
const conn = await d.connect(config);
const result = await d.transact(conn, data);
console.log(result['tx-data']); // Note: 'tx-data' not 'tx_data'
console.log(result['db-before']);
console.log(result['db-after']);
// Using promises
d.connect(config).then(conn => {
return d.transact(conn, data);
}).then(result => {
console.log(result['tx-data']);
});
All functions use camelCase naming. The JavaScript API automatically:
kebab-case → camelCase! and ? suffixeswith → withDb (reserved keyword)Main API Functions:
createDatabase, deleteDatabase, databaseExistsconnect, releasedb, asOf, since, history, withDb, dbWithtransact (async, returns Promise), loadEntitiesq, pull, pullMany, datoms, seekDatoms, entity, entityDbschema, reverseSchematempid, isFiltered, filter, indexRangegcStoragedatahikeVersionNote: transact! from Clojure becomes transact in JavaScript (the ! is removed).
Full TypeScript definitions are automatically generated and included:
import * as d from 'datahike';
interface Config {
store: {
backend: string;
id?: string;
path?: string;
};
'keep-history'?: boolean;
'schema-flexibility'?: string;
}
const config: Config = {
store: { backend: ':memory', id: 'example' }
};
async function example() {
await d.createDatabase(config);
const conn = await d.connect(config);
const db = d.db(conn);
// TypeScript will check types automatically
}
The comprehensive test suite in npm-package/test.js covers all functionality:
Run tests with:
bb npm-test
Tests are automatically run in CI/CD as part of bb check.
Naming is centralized in src/datahike/js/naming.cljc for consistency:
;; Functions to skip (incompatible with JS or aliases)
(def js-skip-list #{'transact}) ; sync version, use transact! instead
;; Conversion rules:
;; database-exists? → databaseExists
;; create-database → createDatabase
;; transact! → transact (! removed)
;; with → withDb (reserved keyword)
datahike.api.specificationjs-skip-list in naming.cljc to excludebb npm-build
This will:
Versions are calculated automatically from config.edn:
major.minor.commit-count0.6.1637 (major: 0, minor: 6, commits: 1637)package.json is generated from package.template.json during buildSee npm-package/PUBLISHING.md for detailed publishing instructions.
Quick workflow:
# 1. Build and test
bb npm-build
# 2. Verify package
cd npm-package && npm pack --dry-run
# 3. Publish as next
npm publish --tag next
The Datalog query API requires EDN string format:
// ✅ Works: EDN string format
const results = await d.q(
'[:find ?name ?age :where [?e :name ?name] [?e :age ?age]]',
db
);
// ❌ Doesn't work: JavaScript object syntax
// const results = await d.q({ find: '?e', where: [...] }, db);
// ✅ Alternative: Use Datoms API for simple queries
const datoms = await d.datoms(db, ':eavt');
The entity function returns ClojureScript objects, not plain JavaScript objects. Use the Pull API for plain data:
// ✅ Recommended: Pull API returns plain objects
const data = await d.pull(db, [':name', ':age'], entityId);
console.log(data.name); // Works
// ⚠️ Entity API returns ClojureScript objects
const entity = await d.entity(db, entityId);
// Accessing attributes requires understanding ClojureScript objects
Shadow-cljs compilation may produce warnings from dependencies:
persistent-sorted-set (harmless, ES2020 feature)filter (expected, intentional override)These can be safely ignored.
Functions are automatically generated from datahike.api.specification by the emit-js-api macro. To add a function:
api-specification in src/datahike/api/specification.cljcjs-skip-list in api_macros.clj if it should be excludednpx shadow-cljs compile npm-releaseIf you need to handle special types, update clj->js-recursive and js->clj-recursive in src/datahike/js/api.cljs.
Published as datahike@next on npm. Install with:
npm install datahike@next
: prefix)Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |