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 an owned collection: Define an owned collection with a specific schema where users can store private data
  3. User data storage: A user stores private data in their collection with create, read, update, and delete (CRUD) capabilities

This showcases Nillion's core value: users own their data, but can selectively share it with applications.

What You'll Learn

  • How builders create owned collections for user data
  • How users store private data with individual access controls
  • How to grant and revoke specific permissions (read/write/execute)
  • How the @nillion/secretvaults library handles encryption and share distribution automatically

Code Reference

  • The completed full tutorial code is here.

Prerequisites

  • MetaMask browser extension
  • Keplr browser extension

1. Get your API key and subscription

You will need an Ethereum and Cosmos wallet (i.e., MetaMask and Keplr) to get your API keys. As a best practice, we recommend setting up separate wallets for development.

  1. Switch to the Testnet network
  2. Connect your developer MetaMask and Keplr wallets
  3. Fund your account with Testnet NIL
  4. Subscribe to nilDB using your subscription wallet

2. Project Setup

Clone the demo repository.

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

Project Structure

src/
app/
layout.tsx
globals.css
page.tsx
profile/page.tsx
components/
Notes.tsx
ProtectedRoute.tsx
context/
NillionContext.tsx
AuthFlowManager.tsx
hooks/
useNillion.ts
usePersistedConnection.ts
useSessionQuery.ts
useInitializeSessionMutation.ts
useLoginMutation.ts
useNillionClient.ts
useNotesCollection.ts
useNotes.ts
types/
NillionState.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 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
    • 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 exists.

src/hooks/useLoginMutation.ts

  • Rehydrates from localStorage
  • Validates the root token
  • Reuses or mints invocation tokens
  • Writes session back to React Query.

Key concepts:

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

5. Collection creation

Before storing notes, we need a collection with a schema. Encrypted fields use %allot in the schema.

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

6. 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
nildb/secretvaults-ts/standard-collection/nextjs-app-metamask-full/src/hooks/useNotes.ts
loading...

8. 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.

src/app/profile/page.tsx:

  • Wrapped with <ProtectedRoute> to ensure only authenticated users can access.
  • 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 }.

9. 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. Create a note - the content is automatically encrypted!
  5. Refresh the page - your session persists

What Just Happened?

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

  1. Users authenticate with MetaMask - no passwords needed
  2. Note titles are plaintext - for easy display and filtering
  3. Note content is encrypted - split into 3 secret shares across nodes
  4. Only the owner can decrypt - using their MetaMask signature
  5. Sessions persist - via NUC tokens stored 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