Skip to main content

Quickstart

This guide demonstrates how to build a passwordless notes application using nilDB.

We will be using secretvaults for private storage, MetaMask for identity, and Nillion's Network User Credentials (NUC) for secure, decentralized authentication.

What You'll Build

In this quickstart, you'll create a simple notes app that requires login via MetaMask and learn:

  1. Builder setup: You (as a builder/application) will register for a Nillion API key
  2. Create a standard collection: Define a standard collection with an encrypted content field
  3. Wallet-scoped data storage: Store and manage a user's notes with create, read, update, and delete (CRUD) operations

This showcases Nillion's core value: builders can preserve privacy by default while storing data securely across multiple nilDB nodes.

What You'll Learn

  • How builders create standard collections with encrypted fields
  • How users authenticate with MetaMask and get a DID-backed NUC session
  • How sessions persist via root token + invocation tokens
  • How to use %share (schema) and %allot (write payload) correctly
  • How the @nillion/secretvaults library handles encryption and share distribution automatically

Code Reference

  • The completed full tutorial code is here.

1. Prerequisites

  • MetaMask browser extension
  • Active nilDB subscription and API key
  • Node.js 20+ and pnpm

Get your nilDB subscription and API key

You only need an EVM wallet (MetaMask) for this flow.

2. Project Setup

Clone the demo repository.

git clone https://github.com/NillionNetwork/blind-module-examples
cd blind-module-examples/nildb/secretvaults-ts/standard-collection/nextjs-app-metamask-full
pnpm install
pnpm run dev

Project Structure

src/
app/
layout.tsx
globals.css
page.tsx
profile/page.tsx
components/
Notes.tsx
ProtectedRoute.tsx
context/
AuthFlowManager.tsx
LogContext.tsx
NillionContext.tsx
NillionState.ts
hooks/
useBuilderProfileQuery.ts
useProfile.ts
useNillion.ts
usePersistedConnection.ts
useSessionQuery.ts
useInitializeSessionMutation.ts
useLoginMutation.ts
useNillionClient.ts
useNotesCollection.ts
useNotes.ts
config.ts

This is the project structure you'll use.

Config file

This configuration is required to connect to the three nilDB nodes.

nildb/secretvaults-ts/standard-collection/nextjs-app-metamask-full/src/config.ts
loading...

3. MetaMask + Session Flow

We subscribed to the nilPay platform using a MetaMask account, so now we want to sign in with that account. This requires interfacing with a web3 wallet and is primarily done in src/context/NillionContext.tsx.

We also use the viem library to detect and prove ownership of the account.

Key Concept:

Signer.fromWeb3() wraps MetaMask's signing capability so Nillion can use it for NUC token creation.

nildb/secretvaults-ts/standard-collection/nextjs-app-metamask-full/src/context/NillionContext.tsx
loading...

Relevant files:

src/hooks/useInitializeSessionMutation.ts:

  • initializeSession():
    • Creates NilauthClient
    • Checks subscriptionStatus
    • Builds SecretVaultBuilderClient.from({ blindfold: { operation: "store" } })
    • Calls refreshRootToken()
    • Mints per-node invocation tokens
    • Ensures builder profile exists (readProfile, then register if needed)
    • Returns { nillionClient, nilauthClient, rootToken, nildbTokens }.
    • On success, saves the session into React Query (["session"]) and persists tokens via usePersistedConnection.

src/context/AuthFlowManager.tsx

  • Decides whether to initialize or log in based on MetaMask connection and whether a stored session already exists.

src/hooks/useLoginMutation.ts

  • Rehydrates from localStorage (rootToken, nildbTokens)
  • Validates the stored root token
  • Reuses invocation tokens when available, otherwise mints fresh tokens
  • Ensures builder profile exists
  • Writes session back to React Query.

src/hooks/usePersistedConnection.ts

  • Persists connection state and session credentials in localStorage
  • Exposes hasStoredSession used by AuthFlowManager

Key concepts:

  • Root token: Master authorization from nilauth
  • Invocation Tokens: Node-specific tokens (one per nilDB node)
  • Blindfold: Enables automatic encryption for %allot fields

4. Collection Creation (Standard Collection)

Before storing notes, we need a standard collection with a schema.

  • In the schema, encrypted fields use %share
  • In write payloads, encrypted values use %allot
nildb/secretvaults-ts/standard-collection/nextjs-app-metamask-full/src/hooks/useNotesCollection.ts
loading...

5. Create, Read, Update, Delete (CRUD) Operations

Key patterns

Notice how content is wrapped in { "%allot": value } when sending.

The SDK automatically:

  1. Detects the %allot marker
  2. Encrypts the value
  3. Splits it into secret shares
  4. Sends one share to each nilDB node

In this example:

  • Notes are written with createStandardData
  • Reads are filtered by walletAddress
  • Updates and deletes use _id filters on the same collection
nildb/secretvaults-ts/standard-collection/nextjs-app-metamask-full/src/hooks/useNotes.ts
loading...

6. UI Layout

src/app/page.tsx:

  • useNillion() to connect to MetaMask, log out, and access state (address/DID)
  • useSessionQuery() to know when the session is ready
  • Displays authentication logs so users can follow session setup progress

src/app/profile/page.tsx:

  • Wrapped with <ProtectedRoute> to ensure only authenticated users can access.
  • Uses useProfile() to display builder profile details
  • Renders <Notes />, which is where CRUD happens

src/components/Notes.tsx:

  • Hook integration
    • Calls useNotes() which wires together:
      • useNotesCollection() (ensures/creates collection with encrypted content schema).
      • useNillionClient() (provides nillionClient + per-node tokens).
      • All CRUD operations
      • Encryption happens in the hook via ensureAllot() which wraps content as { "%allot": string }.

7. Running Your App

After you run your app with pnpm run dev, open http://localhost:3000 and:

  1. Click "Connect with MetaMask"
  2. Approve the MetaMask connection
  3. Wait for session initialization
  4. Open the profile page
  5. Create a note - the content is automatically encrypted
  6. Refresh the page - your session persists
note

During session initialization, MetaMask may prompt you to sign 3 or more times. This is expected: nilDB uses per-node invocation authorization (typically one signature per node) in addition to the root session flow.


What Just Happened?

🎉 Congratulations! You built a privacy-preserving notes app where:

  1. Users authenticate with MetaMask - no passwords needed
  2. A builder profile is created (or reused) automatically during session setup
  3. A standard notes collection is created (or reused) per wallet
  4. Note titles and wallet addresses stay plaintext for filtering/display
  5. Note content is encrypted and split into secret shares across nilDB nodes
  6. Sessions persist via root token + per-node invocation tokens in localStorage
?

Were you able to complete the quickstart?

Advanced Features

Query Operations

// Create and run queries on encrypted data
const query = {
_id: randomUUID(),
name: 'Find Users by Name',
collection: collectionId,
variables: {
searchName: {
description: 'Name to search for',
path: '$.pipeline[0].$match.name',
},
},
pipeline: [{ $match: { name: '' } }, { $count: 'total' }],
};

await builder.createQuery(query);

OpenAPI

You can access the OpenAPI specifications for any node by visiting the following URL pattern: https://{endpoint}/openapi.json, where {endpoint} is replaced with your specific node address. For instance, to view the API specs for the staging node, you would use: https://nildb-stg-n1.nillion.network/openapi.json.

Next Steps

Now that you understand the basics of Nillion private storage, you can:

  • Explore more complex collection schemas
  • Implement query operations on encrypted data
  • Build applications that respect user privacy by default