> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tinycloud.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Node SDK quickstart

> Run a backend script that signs in and verifies its first TinyCloud write

Start here when your code runs in Node.js. You will create a small TypeScript project, generate a disposable development key, and write and read back one record.

## Prerequisites

* Node.js 20 or newer
* Network access to `https://node.tinycloud.xyz`

<Warning>
  The generated key is for this tutorial only. Never put a production wallet key in source control, logs, frontend code, or a shared `.env` file.
</Warning>

## Create the project

```bash theme={null}
mkdir tinycloud-node-quickstart
cd tinycloud-node-quickstart
npm init -y
npm install @tinycloud/node-sdk@2.7.0 dotenv
npm install --save-dev tsx typescript @types/node
npm pkg set scripts.start="tsx index.ts"
```

Generate a new key for the empty tutorial space and exclude it from Git:

```bash theme={null}
node -e "const c=require('node:crypto'),f=require('node:fs');f.writeFileSync('.env','WALLET_PRIVATE_KEY='+c.randomBytes(32).toString('hex')+'\n')"
node -e "require('node:fs').writeFileSync('.gitignore','.env\nnode_modules/\n')"
```

Create `index.ts`:

```typescript theme={null}
import 'dotenv/config';
import { TinyCloudNode } from '@tinycloud/node-sdk';

const privateKey = process.env.WALLET_PRIVATE_KEY;
if (!privateKey) throw new Error('WALLET_PRIVATE_KEY is missing from .env');

async function main() {
  const tc = new TinyCloudNode({
    privateKey,
    host: 'https://node.tinycloud.xyz',
    prefix: 'tinycloud-quickstart',
    autoCreateSpace: true,
  });

  await tc.signIn();

  const saved = await tc.kv.put('first-record', {
    message: 'Hello from TinyCloud',
    writtenAt: new Date().toISOString(),
  });
  if (!saved.ok) throw new Error(`${saved.error.code}: ${saved.error.message}`);

  const loaded = await tc.kv.get<{ message: string }>('first-record');
  if (!loaded.ok) throw new Error(`${loaded.error.code}: ${loaded.error.message}`);

  console.log(JSON.stringify({
    ownerDid: tc.did,
    space: tc.spaceId,
    record: loaded.data.data,
  }, null, 2));
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});
```

## Run and verify

```bash theme={null}
npm start
```

Success prints the owner DID, a space ending in `:tinycloud-quickstart`, and the record read back from that space:

```json theme={null}
{
  "ownerDid": "did:pkh:eip155:1:0x…",
  "space": "tinycloud:pkh:eip155:1:0x…:tinycloud-quickstart",
  "record": {
    "message": "Hello from TinyCloud"
  }
}
```

The exact chain, address, and timestamp will differ. A failed sign-in throws before the write. A failed KV call prints its SDK error code and exits without reporting success.

## Use an existing secret safely

For a real service, replace the disposable `.env` key with your secret manager's runtime injection. Keep `.env` for local development only, retain it in `.gitignore`, and use a wallet dedicated to the service rather than a personal wallet that holds assets.

## Next steps

* [Node authentication and session lifecycle](/guides/authentication/node)
* [KV basic operations](/guides/kv/basic-operations)
* [Receive a delegation](/guides/delegations)
* [Node client overview](/reference/sdk/node)

<Note>
  Verified against `@tinycloud/node-sdk` 2.7.0.
</Note>
