# Extending and composing data schemas

New schemas can extend other schemas by setting a parent schema ID. Remember, you can take any raw schema string and compute a schema ID from it. When registering a new schema that builds upon and extends another, you would specify the raw schema string for the new schema as well as specifying the optional parent schema ID. The parent schema ID will be critical later for deserialising data written to chain.\
\
For schemas that do not extend other schemas (when nothing is available), then one does not need to specify a parent schema ID or can optionally specify the zero value for the bytes32 solidity type.\
\
For maximum composability, all schemas should be public.

### Extension in practice (Example 1)

<pre class="language-typescript"><code class="lang-typescript"><strong>import { SDK } from "@somnia-chain/streams"
</strong><strong>const sdk = new SDK({
</strong>    public: getPublicClient(),
    wallet: getWalletClient(),
})

// The parent schema here will be the GPS schema from the quick start guide
const gpsSchema = `uint64 timestamp, int32 latitude, int32 longitude, int32 altitude, uint32 accuracy, bytes32 entityId, uint256 nonce`
const parentSchemaId = await sdk.streams.computeSchemaId(gpsSchema)

// Lets extend the gps schema and add F1 data since every car will have a gps position
const formulaOneSchema = `uint256 driverNumber`

// We can also extend the gps schema for FR data i.e. aircraft identifier
const flightRadarSchema = `bytes32 ICAO24`

await sdk.streams.registerDataSchemas([
    { schemaName: "gps", schema: gpsSchema },
    { schemaName: "f1", schema: formulaOneSchema, parentSchemaId }, // F1 extends GPS
    { schemaName: "FR", schema: flightRadarSchema, parentSchemaId },// FR extends GPS
])
</code></pre>

The typescript code shows how two new schemas re-use the GPS schema in order to append an additional field

### Extension in practice (Example 2)

Versioned schemas

```typescript
import { SDK } from "@somnia-chain/streams"
const sdk = new SDK({
    public: getPublicClient(),
    wallet: getWalletClient(),
})

const versionSchema = `uint16 version`
const parentSchemaId = await sdk.streams.computeSchemaId(versionSchema)

// Now lets register a person schema with expectation there will be many versions of the person schema
const personSchema = `uint8 age` 
await sdk.streams.registerDataSchemas([
    { schemaName: "version", schema: versionSchema },
    { schemaName: "person", schema: personSchema, parentSchemaId }
])
```

Client's that are reading data associated with the derived schemas, use the SDK to get the fully decoded data since data is retrieved by schema ID (See `getByKey` from the quick start guide). Essentially the SDK does a number of the following pseudo steps:

1. Fetch schema and recursively fetch parent schema until the end of the chain is reached
2. Join all schemas together seperated by comma
3. Spin up the decoder and pass through the raw data stored on-chain
4. Return the decoded data to the caller


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.somnia.network/developer/data-streams/concepts/extending-and-composing-data-schemas.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
