First App
This page shows how to create your first Softadastra JavaScript SDK application.
You will build a small local-first program that opens a Softadastra client, writes a value, reads the value back, prints the result, and closes the client.
The goal is to understand the basic SDK flow before enabling persistence, sync, transport, or discovery.
What you will build
key : app/name
value : Softadastra SDK
size : 1The flow is:
ClientOptions
↓
Client
↓
open
↓
put
↓
get
↓
closeCreate a small app
mkdir softadastra-js-first-app
cd softadastra-js-first-app
npm init -y
npm pkg set type=module
npm install @softadastra/sdk
nano main.jsWrite the first app
Paste this code:
import { Client, ClientOptions } from "@softadastra/sdk";
const client = new Client(
ClientOptions.local("node-local"),
);
const openResult = await client.open();
if (openResult.isErr()) {
console.error(
`failed to open client: ${openResult.error().message}`,
);
process.exit(1);
}
const putResult = await client.put(
"app/name",
"Softadastra SDK",
);
if (putResult.isErr()) {
console.error(
`failed to store value: ${putResult.error().message}`,
);
await client.close();
process.exit(1);
}
const valueResult = await client.get("app/name");
if (valueResult.isErr()) {
console.error(
`failed to read value: ${valueResult.error().message}`,
);
await client.close();
process.exit(1);
}
console.log("key : app/name");
console.log(`value : ${valueResult.value().toString()}`);
console.log(`size : ${client.size()}`);
await client.close();Run the app
node main.jsExpected output:
key : app/name
value : Softadastra SDK
size : 1Understand the code
The SDK import
import { Client, ClientOptions } from "@softadastra/sdk";This gives access to the main public SDK types. For this first app, you only need Client and ClientOptions.
Create client options
const client = new Client(
ClientOptions.local("node-local"),
);ClientOptions.local("node-local") creates a local SDK configuration. The node id is node-local. In local mode, no WAL, transport, or discovery is configured by default.
Open the client
const openResult = await client.open();The client must be opened before use. The SDK uses explicit result values, so you must check the result:
if (openResult.isErr()) {
console.error(
`failed to open client: ${openResult.error().message}`,
);
process.exit(1);
}This is the normal SDK pattern: call operation, check result, handle error, continue only on success.
Write a value
const putResult = await client.put(
"app/name",
"Softadastra SDK",
);This writes a local value. The key is app/name. The value is Softadastra SDK. This is local-first — the write does not require a server, peer, transport, discovery, or cloud access.
Always check the result:
if (putResult.isErr()) {
console.error(
`failed to store value: ${putResult.error().message}`,
);
await client.close();
process.exit(1);
}Read the value
const valueResult = await client.get("app/name");get() reads from local state. Always check the result before reading the value:
if (valueResult.isErr()) {
console.error(
`failed to read value: ${valueResult.error().message}`,
);
await client.close();
process.exit(1);
}
console.log(`value : ${valueResult.value().toString()}`);Check the store size
console.log(`size : ${client.size()}`);After one successful write, the size should be 1.
Close the client
await client.close();This gives the SDK a clean lifecycle: construct → open → use → close.
Run the existing example
If you are inside the JavaScript SDK repository, the same idea already exists as examples/01-local-store.js.
cd ~/softadastra/sdk-js
npm install
npm run examples:local-storeOr directly:
node examples/01-local-store.jsExpected output:
key : app/name
value : Softadastra SDK
size : 1Local repository import
Inside the SDK repository, examples use the local source import:
import { Client, ClientOptions } from "../src/index.js";For external applications, use the package import:
import { Client, ClientOptions } from "@softadastra/sdk";Result and error handling
This is the correct pattern:
const result = await client.get("app/name");
if (result.isErr()) {
console.error(result.error().message);
process.exit(1);
}
console.log(result.value().toString());Avoid this pattern:
const value = (await client.get("app/name")).value();That assumes the operation succeeded. In local-first systems, failures must be visible.
Why local-only first?
The first app uses local mode on purpose:
ClientOptions.local("node-local")This proves the most important Softadastra principle: local work does not require the network.
After this works, you can add features one by one: persistent store, sync state, manual ticks, transport, discovery, metadata.
Make it persistent next
The first app is local and simple. To make it persistent:
const options = ClientOptions.persistent(
"node-persistent",
"data/sdk-store.wal",
);
options.autoFlush = true;
const client = new Client(options);Create the data directory first:
mkdir -p dataInspect sync next
After writing a value:
await client.put("profile/name", "Ada");Inspect sync state:
const state = await client.syncStateInfo();
if (state.isOk()) {
console.log(`outbox : ${state.value().outboxSize}`);
console.log(`queued : ${state.value().queuedCount}`);
console.log(`failed : ${state.value().failedCount}`);
}Run one sync tick:
const tick = await client.tick();
if (tick.isOk()) {
console.log(`batch : ${tick.value().batchSize}`);
}Complete app with cleanup
import { Client, ClientOptions } from "@softadastra/sdk";
const client = new Client(
ClientOptions.local("node-local"),
);
const opened = await client.open();
if (opened.isErr()) {
console.error(`open failed: ${opened.error().message}`);
process.exit(1);
}
const written = await client.put("app/name", "Softadastra SDK");
if (written.isErr()) {
console.error(`put failed: ${written.error().message}`);
await client.close();
process.exit(1);
}
const value = await client.get("app/name");
if (value.isErr()) {
console.error(`get failed: ${value.error().message}`);
await client.close();
process.exit(1);
}
console.log(`value: ${value.value().toString()}`);
await client.close();Common mistakes
Forgetting ESM mode
If you see Cannot use import statement outside a module:
npm pkg set type=moduleForgetting to install the SDK
If you see Cannot find package '@softadastra/sdk':
npm install @softadastra/sdkIgnoring results
Wrong:
await client.put("key", "value");
const value = await client.get("key");
console.log(value.value().toString());Correct:
const value = await client.get("key");
if (value.isErr()) {
console.error(value.error().message);
await client.close();
process.exit(1);
}
console.log(value.value().toString());Forgetting to close the client
After open() succeeds, close the client before exiting:
await client.close();Recommended first workflow
mkdir softadastra-js-first-app
cd softadastra-js-first-app
npm init -y
npm pkg set type=module
npm install @softadastra/sdk
nano main.js
node main.jsThen verify the output:
key : app/name
value : Softadastra SDK
size : 1Summary
Your first JavaScript SDK app uses ClientOptions, Client, open, put, get, size, and close.
The key lesson is: Softadastra can write and read locally without a server or peer. This is the foundation of the JavaScript SDK.
Next step
Continue with the Client API: