What you'll achieve By the end of this guide, you will have established a connection to TerminusDB using the JavaScript client.
Prerequisites
- TerminusDB running locally (Install guide →)
- Node.js 20+ installed
- A terminal
If you haven't run the curl quickstart yet, do that first — it takes 5 minutes and introduces the branch/diff/merge concepts this guide builds on.
TerminusDB must be running
This guide assumes TerminusDB is running on localhost:6363. If you have trouble connecting, see Troubleshooting Connection Failures and Authentication Errors.
Install the client
mkdir my-terminusdb-app && cd my-terminusdb-app
npm init -y
npm install terminusdbCreate a file called index.ts. You will build it up step by step below, or copy the complete file at the end.
Connect to TerminusDB
import TerminusClient from "terminusdb"
const client = new TerminusClient.WOQLClient("http://localhost:6363", {
user: "admin",
organization: "admin",
key: "root",
})
// Verify the connection works
const info = await client.info()
console.log("Connected to TerminusDB", info)What you should see: A server info object with version and storage details. If you see a connection error, check that Docker is running and TerminusDB is on port 6363.
Create a database and insert a document
No schema needed — insert any JSON document with raw_json: true and give it a human-readable ID:
// Create a database (no schema required)
await client.createDatabase("MyDatabase", {
label: "My Database",
comment: "TypeScript quickstart",
schema: false,
})
// Insert a document — choose your own ID, no schema to define
const result = await client.addDocument(
{ "@id": "terminusdb:///data/jane", name: "Jane Smith", email: "jane@example.com", age: 30 },
{ raw_json: true },
)
console.log("Document created:", result)What you should see: ["terminusdb:///data/jane"]. The @id gives the document a stable, human-readable identifier you choose. Schema comes later when you are ready.
Create a branch
Just like git branch, this creates an isolated copy of your data:
// Create a new branch from main
await client.branch("feature")
// Switch to it (like git checkout)
client.checkout("feature")
console.log("Now on branch:", client.checkout())What you should see: Now on branch: feature
Everything you do now happens on feature — main is untouched.
Edit the document on the branch
// Get the document we inserted earlier
const person = await client.getDocument({ id: "terminusdb:///data/jane", as_list: true })
console.log("Current document:", person)
// Update the email on this branch
await client.updateDocument(
{ "@id": "terminusdb:///data/jane", name: "Jane Smith", email: "jane.smith@company.com", age: 30 },
{ raw_json: true },
"",
"Updated Jane's email",
)
console.log("Document updated on feature branch")What you should see: The document retrieved, then confirmation of the update. The change only exists on feature — main still has the original email.
See the diff
This is the moment. TerminusDB can show you exactly what changed between branches — structurally, field by field:
// Compare main to feature — what changed?
const diff = await client.getVersionDiff("main", "feature")
console.log("Changes between main and feature:")
console.log(JSON.stringify(diff, null, 2))What you should see:
[
{
"@id": "terminusdb:///data/jane",
"email": { "@op": "SwapValue", "@before": "jane@example.com", "@after": "jane.smith@company.com" }
}
]What just happened? TerminusDB computed a structural diff — not a line-by-line text diff, but semantic operations (SwapValue) that know exactly which fields changed, what the old values were, and what the new values are. This patch can be applied, reversed, or composed with other patches.
Merge the branch
Bring the changes back to main:
// Switch back to main
client.checkout("main")
// Merge feature into main (like git merge)
await client.rebase({
rebase_from: "admin/MyDatabase/local/branch/feature",
message: "Merge feature: updated Jane's email",
})
console.log("Merged feature into main")What you should see: Merged feature into main
Verify the merge
Confirm the changes are now on main:
// Read the document from main
const updated = await client.getDocument({ id: "terminusdb:///data/jane", as_list: true })
console.log("Person on main after merge:", updated)What you should see: Jane Smith with jane.smith@company.com — the changes from the feature branch are now on main.
What just happened?
You just used your database like a git repository:
- Branched — created an isolated workspace (
feature) without copying data - Edited — made changes that only exist on that branch
- Diffed — asked TerminusDB to show exactly what changed, field by field
- Merged — brought changes back to
maincleanly
This is the core workflow of TerminusDB. Every change is a commit. Every prior state is recoverable. Multiple branches can exist simultaneously — for testing, staging, feature development, or collaboration.
The complete index.ts
Run with npx tsx index.ts:
import TerminusClient from "terminusdb"
async function main() {
// 1. Connect
const client = new TerminusClient.WOQLClient("http://localhost:6363", {
user: "admin",
organization: "admin",
key: "root",
})
// 2. Create database + insert document (no schema)
await client.createDatabase("MyDatabase", {
label: "My Database",
comment: "TypeScript quickstart",
schema: false,
})
const result = await client.addDocument(
{ "@id": "terminusdb:///data/jane", name: "Jane Smith", email: "jane@example.com", age: 30 },
{ raw_json: true },
)
console.log("Document created:", result)
// 3. Branch
await client.branch("feature")
client.checkout("feature")
console.log("Now on branch:", client.checkout())
// 4. Edit on branch
const person = await client.getDocument({ id: "terminusdb:///data/jane", as_list: true })
await client.updateDocument(
{ "@id": "terminusdb:///data/jane", name: "Jane Smith", email: "jane.smith@company.com", age: 30 },
{ raw_json: true },
"",
"Updated Jane's email",
)
console.log("Document updated on feature branch")
// 5. See the diff
const diff = await client.getVersionDiff("main", "feature")
console.log("\nChanges between main and feature:")
console.log(JSON.stringify(diff, null, 2))
// 6. Merge
client.checkout("main")
await client.rebase({
rebase_from: "admin/MyDatabase/local/branch/feature",
message: "Merge feature: updated Jane's email",
})
console.log("\nMerged feature into main")
// 7. Verify
const updated = await client.getDocument({ id: "terminusdb:///data/jane", as_list: true })
console.log("\nPerson on main after merge:", updated)
}
main().catch(console.error)If you've already run this quickstart, delete the database before running again:
await client.deleteDatabase("MyDatabase")Troubleshooting
Error: Connection refused
You see:
Error: connect ECONNREFUSED 127.0.0.1:6363Cause: TerminusDB is not running, or another process is using port 6363.
Fix:
# Check if the container is running
docker ps | grep terminusdb
# If not running, start it
docker start terminusdb
# If it doesn't exist, create it
docker run -d --name terminusdb -p 127.0.0.1:6363:6363 \
-v terminusdb_storage:/app/terminusdb/storage \
terminusdb/terminusdb-serverTroubleshooting Connection Failures →
Error: 401 Unauthorized
You see:
Error: 401 UnauthorizedCause: Wrong username or password. The default local credentials are admin / root.
Fix:
# Verify credentials work
curl -u admin:root http://localhost:6363/api/infoIf you set a custom password via TERMINUSDB_ADMIN_PASS when creating the container, use that value instead of root.
Troubleshooting Authentication Errors →
Error: Database does not exist (404)
You see:
Error: 404 - {"@type":"api:ErrorResponse","api:error":{"@type":"api:UnresolvableAbsoluteDescriptor"}}Cause: You are trying to read/write a database that has not been created yet, or the path is wrong.
Fix:
# List existing databases
curl -u admin:root http://localhost:6363/api/db
# Create the database if missing
curl -u admin:root -X POST "http://localhost:6363/api/db/admin/MyDatabase" \
-H "Content-Type: application/json" \
-d '{"label": "MyDatabase", "comment": "My database"}'Error: Cannot find module 'terminusdb'
You see:
Error [ERR_MODULE_NOT_FOUND]: Cannot find module 'terminusdb'or
Cannot find module 'terminusdb' or its corresponding type declarationsCause: The package is not installed, or you are running from the wrong directory.
Fix:
# Make sure you are in the project directory
cd my-terminusdb-app
# Install the package
npm install terminusdbError: Cannot use import statement outside a module
You see:
SyntaxError: Cannot use import statement outside a moduleCause: You are running the file with node index.ts without ESM support.
Fix: Use npx tsx (recommended) which handles both TypeScript and ESM:
npx tsx index.tsAlternatively, add "type": "module" to your package.json if using plain JavaScript.
Error: Database already exists
You see:
Error: 400 - {"@type":"api:DbCreateErrorResponse","api:error":{"@type":"api:DatabaseAlreadyExists"}}Cause: You ran this quickstart before and the database still exists.
Fix:
await client.deleteDatabase("MyDatabase")Next steps
- Your First Schema — Add type safety to your documents with schema validation
- WOQL Query Guide — Query your data with TerminusDB's pattern-matching query language
- JSON Diff and Patch — Deep dive into structural diff operations
- API Reference — Full TypeScript/JavaScript client API documentation