Identity / Names·Ceramic · EVM (via DID-PKH) · Solana
Ceramic Network
Ceramic is a decentralized event-streaming protocol for mutable, user-owned data. Each document is a verifiable stream controlled by a DID (Ethereum, Solana, Key DIDs supported). ComposeDB is the GraphQL layer on top of Ceramic that gives apps a queryable, schema-driven graph database for identity profiles, verifiable credentials, social graphs, and any user-controlled data — a common backend for self-sovereign identity, reputation, and decentralized social.
- 01user-owned profiles and identity records
- 02storing W3C verifiable credentials off-chain
- 03decentralized social graphs and reputation
- 04cross-app shared identity state
- 05DID-controlled mutable application data
- pnpm add @ceramicnetwork/http-client @composedb/client @didtools/pkh-ethereum dids key-did-resolver
| Variable | Scope | Description |
|---|---|---|
| NEXT_PUBLIC_CERAMIC_URL | Client | URL of a Ceramic node (e.g. self-hosted node or community gateway like https://ceramic-clay.3boxlabs.com). |
| COMPOSEDB_DEFINITION_PATH | Server | Path to the compiled ComposeDB definition file (runtime composite) used by `ComposeClient`. |
| CERAMIC_ADMIN_SEED | Server | 32-byte hex seed for the node's admin DID, used to deploy composites and run indexing. |
Use Ceramic + ComposeDB to store user-owned identity data. Bootstrap a client with `const ceramic = new CeramicClient(NEXT_PUBLIC_CERAMIC_URL); const composeClient = new ComposeClient({ ceramic, definition });`. Authenticate the user with their wallet via `DIDSession.authorize({ resources: composeClient.resources, authMethod: await EthereumWebAuth.getAuthMethod(provider, accountId) })`, then `composeClient.setDID(session.did)`. Read/write with GraphQL: `composeClient.executeQuery(\`query { viewer { profile { name } } }\`)` and `executeQuery(\`mutation Create($i: CreateProfileInput!) { createProfile(input: $i) { document { id } } }\`, { i: { content: { name } } })`. Each document is owned by the user's DID — your app cannot mutate it without their session signature.
- ⚑Ceramic Anchor Service (CAS) anchoring delays mean a write is only globally final after Bitcoin/Ethereum anchoring — usually minutes to a few hours; UIs must show 'pending' state and not assume immediate consensus.
- ⚑ComposeDB requires a node operator to *index* a composite — if you read from a public gateway that hasn't indexed your model, queries silently return empty results. Self-host or coordinate with the gateway operator.
- ⚑DID rotation is a known sharp edge: if a user rotates the wallet behind a did:pkh, their existing streams remain controlled by the old key unless they explicitly update the DID Document. Plan a key-rotation UX or use did:key + delegated CACAO sessions.
- ⚑PII handling: Ceramic streams are *publicly readable by anyone with the streamId* — there is no built-in encryption. For private data, encrypt client-side (e.g. Lit Protocol, libsodium with user-derived keys) before writing.
- ⚑Revocation semantics: deleting a stream is not truly possible; you can only write a 'tombstone' update. Treat all writes as permanent and design accordingly, especially for credentials or social posts.
- ⚑Sybil bypass: Ceramic does not verify identity uniqueness — a single human can create unlimited DIDs and profiles. It is a *data* layer, not a personhood layer. Combine with World ID / PoH / BrightID for Sybil resistance.
- ⚑The product has been re-architected in 2025–2026 toward 'Ceramic ONE' / Recon protocol; older `@ceramicnetwork/core` v3 APIs differ from the new v6+ APIs. Pin versions and read the migration notes before upgrading.