Skip to main content
Version: 0.3.x

Your first composite

ComposeDB provides an abstraction on top of Ceramic streams by leveraging composites, an internal data structure referencing Ceramic model streams and associated metadata. Most of ComposeDB tools and clients interact with various representations of composites.

This page presents how to create your first composite and deploy it to your local Ceramic node, in order to interact with documents on Ceramic.

Running a local Ceramic node


Because ComposeDB is still an experimental feature set built on top of Ceramic, if you want to use it with a Ceramic node, you need to set the CERAMIC_ENABLE_EXPERIMENTAL_COMPOSE_DB environment variable to true, before running a node. Note that ComposeDB is not yet supported on Ceramic mainnet.

The following steps require a local Ceramic node to be running. If you do not already have it running, you can use the following command:

pnpm dlx @ceramicnetwork/cli daemon

Importing a model

Composites can be created by importing existing models. Here we're going to import a simple profile model with the stream ID kjzl6hvfrbw6ca7nidsnrv78x7r4xt0xki71nvwe4j5a3s9wgou8yu3aj8cz38e, that exists on the Clay testnet.

Alternative option

If for some reason the model can't be loaded from the Clay testnet, you can download the composite file directly instead and store it in my-first-composite.json file.

Dependencies required

Make sure you have the listed packages installed before running the code below and your local Ceramic node is connected to the Clay testnet in order to load this model.

import { CeramicClient } from '@ceramicnetwork/http-client'
import { Composite } from '@composedb/devtools'
import { writeEncodedComposite } from '@composedb/devtools-node'

const ceramic = new CeramicClient('http://localhost:7007')
const composite = await Composite.fromModels({
models: ['kjzl6hvfrbw6c7keo17n66rxyo21nqqaa9lh491jz16od43nokz7ksfcvzi6bwc'],

await writeEncodedComposite(composite, 'my-first-composite.json')

More details: Composite.fromModels, writeEncodedComposite

Deploying to a local node

The composite can be deployed from a script or the CLI using the composite file:

Dependencies required

Make sure you have installed the packages imported in the code below before running the script.

import { CeramicClient } from '@ceramicnetwork/http-client'
import { readEncodedComposite } from '@composedb/devtools-node'
import { DID } from 'dids'
import { Ed25519Provider } from 'key-did-provider-ed25519'
import { getResolver } from 'key-did-resolver'
import { fromString } from 'uint8arrays/from-string'

// Hexadecimal-encoded private key for a DID having admin access to the target Ceramic node
// Replace the example key here by your admin private key
const privateKey = fromString('b0cb[...]515f', 'base16')

const did = new DID({
resolver: getResolver(),
provider: new Ed25519Provider(privateKey),
await did.authenticate()

// Replace by the URL of the Ceramic node you want to deploy the Models to
const ceramic = new CeramicClient('http://localhost:7007')
// An authenticated DID with admin access must be set on the Ceramic instance
ceramic.did = did

// Replace by the path to the local encoded composite file
const composite = await readEncodedComposite(ceramic, 'my-first-composite.json')

// Notify the Ceramic node to index the models present in the composite
await composite.startIndexingOn(ceramic)

More details: readEncodedComposite

Interacting using GraphiQL

Once the composite is deployed and the Ceramic node configured, it is possible to start a local HTTP server to interact with the generated GraphQL schema, notably using GraphiQL:

Dependencies required

Make sure you have the @composedb/devtools-node package installed, before running the code below.

import { serveEncodedDefinition } from '@composedb/devtools-node'

const server = await serveEncodedDefinition({
ceramicURL: 'http://localhost:7007',
graphiql: true,
path: new URL('my-first-composite.json', import.meta.url),
port: 5001,

console.log(`Server started on ${server.url}`)

process.on('SIGTERM', () => {
server.close(() => {
console.log('Server stopped')

More details: serveEncodedDefinition

Now you can open http://localhost:5001/graphql in your browser and use the GraphiQL web app to query and mutate the model from your composite.

For example, to create a SimpleProfile instance for the authenticated account:

mutation {
createSimpleProfile(input: { content: { displayName: "Ceramic Dev" } }) {
document {

, and to query the first 10 SimpleProfile instances:

query {
simpleProfileIndex(first: 10) {
edges {
node {

To check the details of the GraphQL schema built from your runtime composite representation, you can use the graphql:schema CLI command:

composedb graphql:schema runtime-composite.json