diff --git a/docs/ensnode.io/config/integrations/starlight/sidebar-topics/integrate.ts b/docs/ensnode.io/config/integrations/starlight/sidebar-topics/integrate.ts
index 18b7500aa..c28584288 100644
--- a/docs/ensnode.io/config/integrations/starlight/sidebar-topics/integrate.ts
+++ b/docs/ensnode.io/config/integrations/starlight/sidebar-topics/integrate.ts
@@ -175,17 +175,37 @@ export const integrateSidebarTopic = {
collapsed: true,
items: [
{
- label: "Overview",
+ label: "Connect",
link: "/docs/integrate/unigraph/examples",
},
{
label: "Domain by Name",
link: "/docs/integrate/unigraph/examples/domain-by-name",
},
+ {
+ label: "Domain Fuzzy Search",
+ link: "/docs/integrate/unigraph/examples/domains-fuzzy-search-by-name",
+ },
+ {
+ label: "Domain Events",
+ link: "/docs/integrate/unigraph/examples/domain-events",
+ },
+ {
+ label: "Subdomains",
+ link: "/docs/integrate/unigraph/examples/subdomains-by-parent-name",
+ },
{
label: "Account Domains",
link: "/docs/integrate/unigraph/examples/account-domains",
},
+ {
+ label: "Latest Registrations",
+ link: "/docs/integrate/unigraph/examples/latest-registrations",
+ },
+ {
+ label: "Expiring Registrations",
+ link: "/docs/integrate/unigraph/examples/expiring-registrations",
+ },
{
label: "Indexing Status",
link: "/docs/integrate/unigraph/examples/indexing-status",
@@ -231,7 +251,7 @@ export const integrateSidebarTopic = {
link: "/docs/integrate/integration-options/ensdb-readers",
},
{
- label: "ENSNode Plugins (data models)",
+ label: "ENSNode Plugins (Data Models)",
link: "/docs/integrate/integration-options/ensnode-plugins",
},
{
diff --git a/docs/ensnode.io/src/components/molecules/EnsDbReaderIntro.astro b/docs/ensnode.io/src/components/molecules/EnsDbReaderIntro.astro
index d1119a101..fa1781b67 100644
--- a/docs/ensnode.io/src/components/molecules/EnsDbReaderIntro.astro
+++ b/docs/ensnode.io/src/components/molecules/EnsDbReaderIntro.astro
@@ -7,5 +7,5 @@ import { Aside } from "@astrojs/starlight/components";
href="/docs/services/ensdb/concepts/glossary#ensdb-writer-schema"
>ensIndexerSchema
schema definition in the Connect section if you haven't already.
+ > in the Connect example if you haven't already.
diff --git a/docs/ensnode.io/src/components/molecules/unigraph-static-example/UnigraphStaticExample.astro b/docs/ensnode.io/src/components/molecules/unigraph-static-example/UnigraphStaticExample.astro
index a4663d928..093a7e1f6 100644
--- a/docs/ensnode.io/src/components/molecules/unigraph-static-example/UnigraphStaticExample.astro
+++ b/docs/ensnode.io/src/components/molecules/unigraph-static-example/UnigraphStaticExample.astro
@@ -38,7 +38,7 @@ const defaultResultNote =
- {sql.resultNote ?? defaultResultNote}
+
@@ -54,8 +54,6 @@ const defaultResultNote =
-
- {ensDbSdk.resultNote ?? defaultResultNote}
-
+
diff --git a/docs/ensnode.io/src/content/docs/docs/integrate/index.mdx b/docs/ensnode.io/src/content/docs/docs/integrate/index.mdx
index f6b7ad883..6f96a9eb0 100644
--- a/docs/ensnode.io/src/content/docs/docs/integrate/index.mdx
+++ b/docs/ensnode.io/src/content/docs/docs/integrate/index.mdx
@@ -155,9 +155,9 @@ The ENS Omnigraph API is a GraphQL API following the Relay specification, so you
Beyond [`enssdk`](/docs/integrate/integration-options/enssdk), [`enskit`](/docs/integrate/integration-options/enskit), and the [Omnigraph GraphQL API](/docs/integrate/integration-options/omnigraph-graphql-api), ENSNode exposes a deeper set of integration surfaces for advanced use cases:
- **[ENSDb (SQL)](/docs/integrate/integration-options/ensdb)** — query the indexed ENSv1 and ENSv2 datasets directly via SQL for custom analytics or your own service layer, from any language with a Postgres driver.
-- **[ENSDb Writers (Indexers)](/docs/integrate/integration-options/ensdb-writers)** — build your own ENSDb Writer to index ENS data into your own ENSDb instance.
-- **[ENSDb Readers](/docs/integrate/integration-options/ensdb-readers)** — build your own ENSDb Reader to query your own ENSDb instance through any interface of your choice.
-- **[ENSNode Plugins](/docs/integrate/integration-options/ensnode-plugins)** — define how onchain data should be indexed into ENSDb.
+- **[ENSDb Writers (Indexers)](/docs/integrate/integration-options/ensdb-writers)** — enable all other layers of the ENSNode stack to build on your custom indexing engine.
+- **[ENSDb Readers (Custom APIs)](/docs/integrate/integration-options/ensdb-readers)** — build your own custom APIs and services on top of ENSDb using any programming language or framework.
+- **[ENSNode Plugins (Indexed Data Models)](/docs/integrate/integration-options/ensnode-plugins)** — define how onchain data should be indexed into ENSDb.
- **[enscli (CLI)](/docs/integrate/integration-options/enscli)** — resolve names, look up records, and run ad-hoc Omnigraph queries from the terminal — built for humans and AI agents alike.
- **[ensskills (AI agents)](/docs/integrate/integration-options/ensskills)** — a curated set of skills that gives AI coding agents a well-defined contract for working with ENS.
- **[ensdb-cli (ENSDb Snapshots)](/docs/integrate/integration-options/ensdb-cli)** — bootstrap a fresh ENSDb in minutes from portable, versioned snapshots instead of waiting days on a full historical backfill.
diff --git a/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/account-domains.mdx b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/account-domains.mdx
index c157b6595..a721b5ccf 100644
--- a/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/account-domains.mdx
+++ b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/account-domains.mdx
@@ -8,47 +8,17 @@ sidebar:
import UnigraphStaticExample from "@components/molecules/unigraph-static-example/UnigraphStaticExample.astro";
import EnsDbWriterSchemaIntro from "@components/molecules/EnsDbWriterSchemaIntro.astro";
import EnsDbReaderIntro from "@components/molecules/EnsDbReaderIntro.astro";
-
-export const resultJson = [
- {
- type: "ENSv1Domain",
- count: 2
- },
- {
- type: "ENSv2Domain",
- count: 14
- }
-];
-
-export const sqlExampleSnippet = `SELECT type, count(*) FROM ensindexer_0.domains
-WHERE owner_id = '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
-GROUP BY type;
-`;
-
-export const tsExampleSnippet = `import { count, eq } from "drizzle-orm";
-
-const counts = await ensDb
-\t.select({ type: ensIndexerSchema.domain.type, count: count() })
-\t.from(ensIndexerSchema.domain)
-\t.where(eq(ensIndexerSchema.domain.ownerId, "0x70997970c51812dc3a010c7d01b50e0d17dc79c8"))
-\t.groupBy(ensIndexerSchema.domain.type);
-`
+import { exampleAccountDomains } from "@data/unigraph-examples/account-domains";
:::caution[`unigraph` plugin required]
Performing SQL queries on the ENS Unigraph requires that you have the `unigraph` plugin activated in your ENSNode instance. [Learn more](/docs/services/ensindexer/usage/configuration)
:::
-Count the Domains owned by an address, grouped by Domain `type` (`ENSv1Domain` vs `ENSv2Domain`) — a single query spanning both protocol versions. See [Connect](/docs/integrate/unigraph/examples) for setup.
+Fetch the Domains owned by an address (across both ENSv1 and ENSv2), including each Domain's `type` (`ENSv1Domain` vs `ENSv2Domain`). See [Connect](/docs/integrate/unigraph/examples) for setup.
diff --git a/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/domain-by-name.mdx b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/domain-by-name.mdx
index bc80cedd1..f63db6276 100644
--- a/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/domain-by-name.mdx
+++ b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/domain-by-name.mdx
@@ -8,50 +8,7 @@ sidebar:
import UnigraphStaticExample from "@components/molecules/unigraph-static-example/UnigraphStaticExample.astro";
import EnsDbWriterSchemaIntro from "@components/molecules/EnsDbWriterSchemaIntro.astro";
import EnsDbReaderIntro from "@components/molecules/EnsDbReaderIntro.astro";
-
-export const unigraphSqlResultJson = [
- {
- id: "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835",
- type: "ENSv1Domain",
- canonical_name: "vitalik.eth",
- canonical_node: "0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835",
- owner_id: "0x220866b1a2219f40e72f5c628b65d54268ca3a9d",
- },
-];
-
-export const ensDbSdkResultJson = [
- {
- id: "1-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835",
- type: "ENSv1Domain",
- canonicalName: "vitalik.eth",
- canonicalNode: "0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835",
- ownerId: "0x220866b1a2219f40e72f5c628b65d54268ca3a9d",
- },
-];
-
-export const sqlExampleSnippet = `SELECT
- id,
- type,
- canonical_name,
- canonical_node,
- owner_id
-FROM ensindexer_0.domains
-WHERE canonical_name = 'vitalik.eth';`
-
-export const tsExampleSnippet = `import { eq } from "drizzle-orm";
-
-const [vitalik] = await ensDb
-\t.select({
-\t\tid: ensIndexerSchema.domain.id,
-\t\ttype: ensIndexerSchema.domain.type,
-\t\tcanonicalName: ensIndexerSchema.domain.canonicalName,
-\t\tcanonicalNode: ensIndexerSchema.domain.canonicalNode,
-\t\townerId: ensIndexerSchema.domain.ownerId,
-\t})
-\t.from(ensIndexerSchema.domain)
-\t.where(eq(ensIndexerSchema.domain.canonicalName, "vitalik.eth"));
-
-console.log(vitalik);`
+import { exampleDomainByName } from "@data/unigraph-examples/domain-by-name";
:::caution[`unigraph` plugin required]
Performing SQL queries on the ENS Unigraph requires that you have the `unigraph` plugin activated in your ENSNode instance. [Learn more](/docs/services/ensindexer/usage/configuration)
@@ -78,9 +35,9 @@ Canonical fields are populated on every Domain reachable from the canonical root
:::
-
+
diff --git a/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/domain-events.mdx b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/domain-events.mdx
new file mode 100644
index 000000000..47a0838e7
--- /dev/null
+++ b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/domain-events.mdx
@@ -0,0 +1,29 @@
+---
+title: Domain Events
+description: Fetch recent events for a Domain from the ENS Unigraph by its canonical name.
+sidebar:
+ label: Domain Events
+---
+
+import UnigraphStaticExample from "@components/molecules/unigraph-static-example/UnigraphStaticExample.astro";
+import EnsDbWriterSchemaIntro from "@components/molecules/EnsDbWriterSchemaIntro.astro";
+import EnsDbReaderIntro from "@components/molecules/EnsDbReaderIntro.astro";
+import { exampleDomainEvents } from "@data/unigraph-examples/domain-events";
+
+:::caution[`unigraph` plugin required]
+Performing SQL queries on the ENS Unigraph requires that you have the `unigraph` plugin activated in your ENSNode instance. [Learn more](/docs/services/ensindexer/usage/configuration)
+:::
+
+Fetch recent events for a Domain by its canonical name. This example joins the `events`, `domain_events`, and `domains` tables to retrieve domain events associated with the `vitalik.eth` name. See [Connect](/docs/integrate/unigraph/examples) for setup.
+
+:::note[Canonical fields]
+Canonical fields are populated on every Domain reachable from the canonical root, across both ENSv1 and ENSv2 — query them uniformly without branching by `type`. In SQL, these columns are `canonical_name`, `canonical_path`, `canonical_node`, and `canonical_depth`; in `ensdb-sdk`, the corresponding fields are `canonicalName`, `canonicalPath`, `canonicalNode`, and `canonicalDepth`.
+:::
+
+
+
+
+
diff --git a/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/domains-fuzzy-search-by-name.mdx b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/domains-fuzzy-search-by-name.mdx
new file mode 100644
index 000000000..2d7eacbd3
--- /dev/null
+++ b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/domains-fuzzy-search-by-name.mdx
@@ -0,0 +1,25 @@
+---
+title: Fuzzy Search for ENS Names
+description: Perform a fuzzy search for ENS names.
+sidebar:
+ label: Fuzzy Search
+---
+
+import UnigraphStaticExample from "@components/molecules/unigraph-static-example/UnigraphStaticExample.astro";
+import EnsDbWriterSchemaIntro from "@components/molecules/EnsDbWriterSchemaIntro.astro";
+import EnsDbReaderIntro from "@components/molecules/EnsDbReaderIntro.astro";
+import { exampleDomainsFuzzySearchByName } from "@data/unigraph-examples/domains-fuzzy-search-by-name";
+
+:::caution[`unigraph` plugin required]
+Performing SQL queries on the ENS Unigraph requires that you have the `unigraph` plugin activated in your ENSNode instance. [Learn more](/docs/services/ensindexer/usage/configuration)
+:::
+
+Fetch Domains with names similar to a query string, ranked by similarity. This example uses PostgreSQL's `pg_trgm` extension, which provides the `%` operator for fuzzy matching and the `similarity()` function for ranking results. See [Connect](/docs/integrate/unigraph/examples) for setup.
+
+
+
+
+
diff --git a/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/expiring-registrations.mdx b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/expiring-registrations.mdx
new file mode 100644
index 000000000..695150df0
--- /dev/null
+++ b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/expiring-registrations.mdx
@@ -0,0 +1,25 @@
+---
+title: Expiring ENS Registrations
+description: Fetch ENS registrations that are about to expire.
+sidebar:
+ label: Expiring Registrations
+---
+
+import UnigraphStaticExample from "@components/molecules/unigraph-static-example/UnigraphStaticExample.astro";
+import EnsDbWriterSchemaIntro from "@components/molecules/EnsDbWriterSchemaIntro.astro";
+import EnsDbReaderIntro from "@components/molecules/EnsDbReaderIntro.astro";
+import { exampleExpiringRegistrations } from "@data/unigraph-examples/expiring-registrations";
+
+:::caution[`unigraph` plugin required]
+Performing SQL queries on the ENS Unigraph requires that you have the `unigraph` plugin activated in your ENSNode instance. [Learn more](/docs/services/ensindexer/usage/configuration)
+:::
+
+Fetch Domains with registrations expiring within a certain timeframe. This example uses a simple `WHERE` clause to filter for Domains with `expiry` between the current time and a specified future time (e.g., 3 days from now). See [Connect](/docs/integrate/unigraph/examples) for setup.
+
+
+
+
+
diff --git a/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/indexing-status.mdx b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/indexing-status.mdx
index 000984ac8..791e9bca6 100644
--- a/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/indexing-status.mdx
+++ b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/indexing-status.mdx
@@ -1,6 +1,6 @@
---
title: Indexing Status
-description: Read the indexing status snapshot for an ENSIndexer instance from ENSDb.
+description: Read the indexing status snapshot for an ENSDb Writer instance from ENSDb.
sidebar:
label: Indexing Status
---
@@ -8,141 +8,17 @@ sidebar:
import UnigraphStaticExample from "@components/molecules/unigraph-static-example/UnigraphStaticExample.astro";
import EnsNodeSchemaIntro from "@components/molecules/EnsNodeSchemaIntro.astro";
import EnsDbReaderIntro from "@components/molecules/EnsDbReaderIntro.astro";
-
-export const ensDbSdkResultJson = {
- indexingStatus: {
- strategy: "omnichain",
- snapshotTime: 1779795066,
- omnichainSnapshot: {
- chains: {
- 1: {
- config: {
- rangeType: "left-bounded",
- startBlock: {
- number: 3327417,
- timestamp: 1489165544,
- },
- },
- chainStatus: "chain-backfill",
- backfillEndBlock: {
- number: 25171597,
- timestamp: 1779703391,
- },
- latestIndexedBlock: {
- number: 21224717,
- timestamp: 1732054691,
- },
- },
- 10: {
- config: {
- rangeType: "left-bounded",
- startBlock: {
- number: 110393959,
- timestamp: 1696386695,
- },
- },
- chainStatus: "chain-backfill",
- backfillEndBlock: {
- number: 152052671,
- timestamp: 1779704119,
- },
- latestIndexedBlock: {
- number: 128226309,
- timestamp: 1732051395,
- },
- },
- 8453: {
- config: {
- rangeType: "left-bounded",
- startBlock: {
- number: 17522624,
- timestamp: 1721834595,
- },
- },
- chainStatus: "chain-backfill",
- backfillEndBlock: {
- number: 46457386,
- timestamp: 1779704119,
- },
- latestIndexedBlock: {
- number: 22632818,
- timestamp: 1732054983,
- },
- },
- 42161: {
- config: {
- rangeType: "left-bounded",
- startBlock: {
- number: 349263357,
- timestamp: 1750406457,
- },
- },
- chainStatus: "chain-queued",
- },
- 59144: {
- config: {
- rangeType: "left-bounded",
- startBlock: {
- number: 6682888,
- timestamp: 1720768992,
- },
- },
- chainStatus: "chain-backfill",
- backfillEndBlock: {
- number: 30774477,
- timestamp: 1779703911,
- },
- latestIndexedBlock: {
- number: 12280006,
- timestamp: 1732054967,
- },
- },
- 534352: {
- config: {
- rangeType: "left-bounded",
- startBlock: {
- number: 16604272,
- timestamp: 1750406415,
- },
- },
- chainStatus: "chain-queued",
- },
- },
- omnichainStatus: "omnichain-backfill",
- omnichainIndexingCursor: 1732054983,
- },
- slowestChainIndexingCursor: 1732054983,
- }
-}
-
-export const unigraphSqlResultJson = {
- indexing_status_snapshot: ensDbSdkResultJson.indexingStatus,
-};
-
-export const sqlExampleSnippet = `-- Indexing status snapshot for the \`ensindexer_0\` ENSIndexer Schema
-SELECT value -> 'indexingStatus' as indexing_status_snapshot
-FROM ensnode.metadata
-WHERE ens_indexer_schema_name = 'ensindexer_0'
-AND key = 'indexing_metadata_context';
-`;
-
-export const tsExampleSnippet = `import { IndexingMetadataContextStatusCodes } from "@ensnode/ensdb-sdk";
-
-const indexingMetadataContext = await ensDbReader.getIndexingMetadataContext();
-if (indexingMetadataContext.statusCode === IndexingMetadataContextStatusCodes.Initialized) {
-\tconst { indexingStatus } = indexingMetadataContext;
-\tconsole.log({ indexingStatus });
-}`;
+import { exampleIndexingStatus } from "@data/unigraph-examples/indexing-status";
:::caution[`unigraph` plugin required]
Performing SQL queries on the ENS Unigraph requires that you have the `unigraph` plugin activated in your ENSNode instance. [Learn more](/docs/services/ensindexer/usage/configuration)
:::
-Read the indexing status snapshot for an ENSIndexer instance from the shared `ensnode.metadata` table. See [Connect](/docs/integrate/unigraph/examples) for setup.
+Read the indexing status snapshot for an ENSDb Writer instance from the shared `ensnode.metadata` table. See [Connect](/docs/integrate/unigraph/examples) for setup.
diff --git a/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/latest-registrations.mdx b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/latest-registrations.mdx
new file mode 100644
index 000000000..167336fe2
--- /dev/null
+++ b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/latest-registrations.mdx
@@ -0,0 +1,25 @@
+---
+title: Latest ENS Registrations
+description: Fetch the latest ENS registrations.
+sidebar:
+ label: Latest Registrations
+---
+
+import UnigraphStaticExample from "@components/molecules/unigraph-static-example/UnigraphStaticExample.astro";
+import EnsDbWriterSchemaIntro from "@components/molecules/EnsDbWriterSchemaIntro.astro";
+import EnsDbReaderIntro from "@components/molecules/EnsDbReaderIntro.astro";
+import { exampleLatestRegistrations } from "@data/unigraph-examples/latest-registrations";
+
+:::caution[`unigraph` plugin required]
+Performing SQL queries on the ENS Unigraph requires that you have the `unigraph` plugin activated in your ENSNode instance. [Learn more](/docs/services/ensindexer/usage/configuration)
+:::
+
+Fetch the latest registrations and their associated Domains. See [Connect](/docs/integrate/unigraph/examples) for setup.
+
+
+
+
+
diff --git a/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/subdomains-by-parent-name.mdx b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/subdomains-by-parent-name.mdx
new file mode 100644
index 000000000..e323095f2
--- /dev/null
+++ b/docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/subdomains-by-parent-name.mdx
@@ -0,0 +1,25 @@
+---
+title: Subdomains
+description: Subdomains under an ENS name.
+sidebar:
+ label: Subdomains
+---
+
+import UnigraphStaticExample from "@components/molecules/unigraph-static-example/UnigraphStaticExample.astro";
+import EnsDbWriterSchemaIntro from "@components/molecules/EnsDbWriterSchemaIntro.astro";
+import EnsDbReaderIntro from "@components/molecules/EnsDbReaderIntro.astro";
+import { exampleSubdomainsByParentName } from "@data/unigraph-examples/subdomains-by-parent-name";
+
+:::caution[`unigraph` plugin required]
+Performing SQL queries on the ENS Unigraph requires that you have the `unigraph` plugin activated in your ENSNode instance. [Learn more](/docs/services/ensindexer/usage/configuration)
+:::
+
+Get a list of subdomains for the `eth` domain, including their Domain `type` (`ENSv1Domain` vs `ENSv2Domain`) — a single query spanning both protocol versions. See [Connect](/docs/integrate/unigraph/examples) for setup.
+
+
+
+
+
diff --git a/docs/ensnode.io/src/data/unigraph-examples/account-domains.ts b/docs/ensnode.io/src/data/unigraph-examples/account-domains.ts
new file mode 100644
index 000000000..27347cc06
--- /dev/null
+++ b/docs/ensnode.io/src/data/unigraph-examples/account-domains.ts
@@ -0,0 +1,203 @@
+import { outputSource } from "./utils";
+import type { QueryExample } from "./types";
+
+const resultNote = outputSource("V2 Sepolia");
+
+/**
+ * Example query for fetching Domains by their owner's address,
+ * demonstrating the use of canonical fields to query across both ENSv1 and
+ * ENSv2 domains without branching by protocol version.
+ */
+export const exampleAccountDomains = {
+ sql: {
+ codeSnippet: `SELECT
+ d.type,
+ d.canonical_name,
+ d.canonical_node,
+ d.id,
+ d.owner_id
+FROM "ensindexer_0".domains d
+WHERE d.canonical = true
+AND d.owner_id = '0xffffffffff52d316b7bd028358089bc8066b8f80'
+ORDER BY d.canonical_name
+LIMIT 10;`,
+ result: [
+ {
+ type: "ENSv1Domain",
+ canonical_name:
+ "[3ad05e2a5922916840bc1e5e6039f00b27cbabf8d0428abce062aa2011307374].addr.reverse",
+ canonical_node: "0xd3947f90d04d7f41f973f09ad7dbdb34cb7463359369e6cf1663bbf928d66e53",
+ id: "11155111-0xb6fb46e1458915dd828633d91e1df8e4c3f2d4dd-0xd3947f90d04d7f41f973f09ad7dbdb34cb7463359369e6cf1663bbf928d66e53",
+ owner_id: "0xffffffffff52d316b7bd028358089bc8066b8f80",
+ },
+ {
+ type: "ENSv1Domain",
+ canonical_name: "[52602a50858115661619fb28cf543ee766c182e0be6743c72d5bd674b3d12686].eth",
+ canonical_node: "0xe91ce3506cd47457c2b3f04c2736875ca1d17ed74bf1a328a7e64cca5ae8c94b",
+ id: "11155111-0xb6fb46e1458915dd828633d91e1df8e4c3f2d4dd-0xe91ce3506cd47457c2b3f04c2736875ca1d17ed74bf1a328a7e64cca5ae8c94b",
+ owner_id: "0xffffffffff52d316b7bd028358089bc8066b8f80",
+ },
+ {
+ type: "ENSv1Domain",
+ canonical_name:
+ "[8268685e13ae6bbfa54901f2954f9fcf80839ffa102fe7146b930623ce9bd7f0].addr.reverse",
+ canonical_node: "0x21c356e778799bfddf59a5683c04f6b08710d7c198fef466cc697563b2210785",
+ id: "11155111-0xb6fb46e1458915dd828633d91e1df8e4c3f2d4dd-0x21c356e778799bfddf59a5683c04f6b08710d7c198fef466cc697563b2210785",
+ owner_id: "0xffffffffff52d316b7bd028358089bc8066b8f80",
+ },
+ {
+ type: "ENSv1Domain",
+ canonical_name: "[d90db363b8bc1371f7d738d264ff7294bfc5636f907c467adf68321a3c6d8188].eth",
+ canonical_node: "0x08c0f01c419a8971af6b3eefe2a8bba1556cccf1163df60b1cdbcab632c8ab48",
+ id: "11155111-0xb6fb46e1458915dd828633d91e1df8e4c3f2d4dd-0x08c0f01c419a8971af6b3eefe2a8bba1556cccf1163df60b1cdbcab632c8ab48",
+ owner_id: "0xffffffffff52d316b7bd028358089bc8066b8f80",
+ },
+ {
+ type: "ENSv1Domain",
+ canonical_name:
+ "[d99fc3d8237200c7122431276a337421cf793f51276873df5a54cc482fdbe685].addr.reverse",
+ canonical_node: "0x4fc87044c0adc4a0c996b9dafe3a4889e72fe0745fc76f18151b81ed73582218",
+ id: "11155111-0xb6fb46e1458915dd828633d91e1df8e4c3f2d4dd-0x4fc87044c0adc4a0c996b9dafe3a4889e72fe0745fc76f18151b81ed73582218",
+ owner_id: "0xffffffffff52d316b7bd028358089bc8066b8f80",
+ },
+ {
+ type: "ENSv2Domain",
+ canonical_name: "eth",
+ canonical_node: "0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae",
+ id: "11155111-0x835f0b284e78cd3f358bcf6cba3b53809f09b79e-35894389512221139346028120028875095598761990588366713962827482865183915769856",
+ owner_id: "0xffffffffff52d316b7bd028358089bc8066b8f80",
+ },
+ {
+ type: "ENSv2Domain",
+ canonical_name: "reverse",
+ canonical_node: "0xa097f6721ce401e757d1223a763fef49b8b5f90bb18567ddb86fd205dff71d34",
+ id: "11155111-0x835f0b284e78cd3f358bcf6cba3b53809f09b79e-100753657518907091865523951670693454610893379027273088370152078482136467767296",
+ owner_id: "0xffffffffff52d316b7bd028358089bc8066b8f80",
+ },
+ {
+ type: "ENSv1Domain",
+ canonical_name: "reverse",
+ canonical_node: "0xa097f6721ce401e757d1223a763fef49b8b5f90bb18567ddb86fd205dff71d34",
+ id: "11155111-0xb6fb46e1458915dd828633d91e1df8e4c3f2d4dd-0xa097f6721ce401e757d1223a763fef49b8b5f90bb18567ddb86fd205dff71d34",
+ owner_id: "0xffffffffff52d316b7bd028358089bc8066b8f80",
+ },
+ {
+ type: "ENSv2Domain",
+ canonical_name: "sfmpfv44d0mig.eth",
+ canonical_node: "0x9b365136312d7ee6e232e3c98e459bc8667ec818c47fbbc55bb5e23d0a21e8cc",
+ id: "11155111-0x64c81210d0e580cfc7746f3fb910bf0e8f6378e1-30078755955643454526763071980293195785165410039216352470119925106082295316480",
+ owner_id: "0xffffffffff52d316b7bd028358089bc8066b8f80",
+ },
+ {
+ type: "ENSv2Domain",
+ canonical_name: "sfmpfvtoicv2ok.eth",
+ canonical_node: "0x7d0c27336cf9d51c3fc8f29ef4ef69df9cd4a8ec983e3e17d457a8de6013f3c5",
+ id: "11155111-0x64c81210d0e580cfc7746f3fb910bf0e8f6378e1-49509597771493908415463190501045916291230588437784211605615168713991762477056",
+ owner_id: "0xffffffffff52d316b7bd028358089bc8066b8f80",
+ },
+ ],
+ resultNote,
+ },
+ sdk: {
+ codeSnippet: `import { and, eq, asc } from "drizzle-orm";
+
+const owner = "0xffffffffff52d316b7bd028358089bc8066b8f80";
+const limit = 10;
+
+const accountDomains = await ensDb
+ .select({
+ canonicalName: ensIndexerSchema.domain.canonicalName,
+ canonicalNode: ensIndexerSchema.domain.canonicalNode,
+ type: ensIndexerSchema.domain.type,
+ id: ensIndexerSchema.domain.id,
+ ownerId: ensIndexerSchema.domain.ownerId,
+ })
+ .from(ensIndexerSchema.domain)
+ .where(
+ and(
+ eq(ensIndexerSchema.domain.ownerId, owner),
+ eq(ensIndexerSchema.domain.canonical, true),
+ ),
+ )
+ .orderBy(asc(ensIndexerSchema.domain.canonicalName))
+ .limit(limit);
+
+console.log(accountDomains);`,
+ result: [
+ {
+ type: "ENSv1Domain",
+ canonicalName:
+ "[3ad05e2a5922916840bc1e5e6039f00b27cbabf8d0428abce062aa2011307374].addr.reverse",
+ canonicalNode: "0xd3947f90d04d7f41f973f09ad7dbdb34cb7463359369e6cf1663bbf928d66e53",
+ id: "11155111-0xb6fb46e1458915dd828633d91e1df8e4c3f2d4dd-0xd3947f90d04d7f41f973f09ad7dbdb34cb7463359369e6cf1663bbf928d66e53",
+ ownerId: "0xffffffffff52d316b7bd028358089bc8066b8f80",
+ },
+ {
+ type: "ENSv1Domain",
+ canonicalName: "[52602a50858115661619fb28cf543ee766c182e0be6743c72d5bd674b3d12686].eth",
+ canonicalNode: "0xe91ce3506cd47457c2b3f04c2736875ca1d17ed74bf1a328a7e64cca5ae8c94b",
+ id: "11155111-0xb6fb46e1458915dd828633d91e1df8e4c3f2d4dd-0xe91ce3506cd47457c2b3f04c2736875ca1d17ed74bf1a328a7e64cca5ae8c94b",
+ ownerId: "0xffffffffff52d316b7bd028358089bc8066b8f80",
+ },
+ {
+ type: "ENSv1Domain",
+ canonicalName:
+ "[8268685e13ae6bbfa54901f2954f9fcf80839ffa102fe7146b930623ce9bd7f0].addr.reverse",
+ canonicalNode: "0x21c356e778799bfddf59a5683c04f6b08710d7c198fef466cc697563b2210785",
+ id: "11155111-0xb6fb46e1458915dd828633d91e1df8e4c3f2d4dd-0x21c356e778799bfddf59a5683c04f6b08710d7c198fef466cc697563b2210785",
+ ownerId: "0xffffffffff52d316b7bd028358089bc8066b8f80",
+ },
+ {
+ type: "ENSv1Domain",
+ canonicalName: "[d90db363b8bc1371f7d738d264ff7294bfc5636f907c467adf68321a3c6d8188].eth",
+ canonicalNode: "0x08c0f01c419a8971af6b3eefe2a8bba1556cccf1163df60b1cdbcab632c8ab48",
+ id: "11155111-0xb6fb46e1458915dd828633d91e1df8e4c3f2d4dd-0x08c0f01c419a8971af6b3eefe2a8bba1556cccf1163df60b1cdbcab632c8ab48",
+ ownerId: "0xffffffffff52d316b7bd028358089bc8066b8f80",
+ },
+ {
+ type: "ENSv1Domain",
+ canonicalName:
+ "[d99fc3d8237200c7122431276a337421cf793f51276873df5a54cc482fdbe685].addr.reverse",
+ canonicalNode: "0x4fc87044c0adc4a0c996b9dafe3a4889e72fe0745fc76f18151b81ed73582218",
+ id: "11155111-0xb6fb46e1458915dd828633d91e1df8e4c3f2d4dd-0x4fc87044c0adc4a0c996b9dafe3a4889e72fe0745fc76f18151b81ed73582218",
+ ownerId: "0xffffffffff52d316b7bd028358089bc8066b8f80",
+ },
+ {
+ type: "ENSv2Domain",
+ canonicalName: "eth",
+ canonicalNode: "0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae",
+ id: "11155111-0x835f0b284e78cd3f358bcf6cba3b53809f09b79e-35894389512221139346028120028875095598761990588366713962827482865183915769856",
+ ownerId: "0xffffffffff52d316b7bd028358089bc8066b8f80",
+ },
+ {
+ type: "ENSv2Domain",
+ canonicalName: "reverse",
+ canonicalNode: "0xa097f6721ce401e757d1223a763fef49b8b5f90bb18567ddb86fd205dff71d34",
+ id: "11155111-0x835f0b284e78cd3f358bcf6cba3b53809f09b79e-100753657518907091865523951670693454610893379027273088370152078482136467767296",
+ ownerId: "0xffffffffff52d316b7bd028358089bc8066b8f80",
+ },
+ {
+ type: "ENSv1Domain",
+ canonicalName: "reverse",
+ canonicalNode: "0xa097f6721ce401e757d1223a763fef49b8b5f90bb18567ddb86fd205dff71d34",
+ id: "11155111-0xb6fb46e1458915dd828633d91e1df8e4c3f2d4dd-0xa097f6721ce401e757d1223a763fef49b8b5f90bb18567ddb86fd205dff71d34",
+ ownerId: "0xffffffffff52d316b7bd028358089bc8066b8f80",
+ },
+ {
+ type: "ENSv2Domain",
+ canonicalName: "sfmpfv44d0mig.eth",
+ canonicalNode: "0x9b365136312d7ee6e232e3c98e459bc8667ec818c47fbbc55bb5e23d0a21e8cc",
+ id: "11155111-0x64c81210d0e580cfc7746f3fb910bf0e8f6378e1-30078755955643454526763071980293195785165410039216352470119925106082295316480",
+ ownerId: "0xffffffffff52d316b7bd028358089bc8066b8f80",
+ },
+ {
+ type: "ENSv2Domain",
+ canonicalName: "sfmpfvtoicv2ok.eth",
+ canonicalNode: "0x7d0c27336cf9d51c3fc8f29ef4ef69df9cd4a8ec983e3e17d457a8de6013f3c5",
+ id: "11155111-0x64c81210d0e580cfc7746f3fb910bf0e8f6378e1-49509597771493908415463190501045916291230588437784211605615168713991762477056",
+ ownerId: "0xffffffffff52d316b7bd028358089bc8066b8f80",
+ },
+ ],
+ resultNote,
+ },
+} satisfies QueryExample;
diff --git a/docs/ensnode.io/src/data/unigraph-examples/domain-by-name.ts b/docs/ensnode.io/src/data/unigraph-examples/domain-by-name.ts
new file mode 100644
index 000000000..46ef0ee76
--- /dev/null
+++ b/docs/ensnode.io/src/data/unigraph-examples/domain-by-name.ts
@@ -0,0 +1,81 @@
+import { outputSource } from "./utils";
+import type { QueryExample } from "./types";
+
+const resultNote = outputSource("V2 Sepolia");
+
+/**
+ * Example query for fetching Domains by a canonical name,
+ * demonstrating the use of canonical fields to query across both ENSv1 and
+ * ENSv2 domains without branching by protocol version.
+ */
+export const exampleDomainByName = {
+ sql: {
+ codeSnippet: `SELECT
+ id,
+ type,
+ canonical_name,
+ canonical_node,
+ owner_id
+FROM "ensindexer_0".domains
+WHERE canonical_name = 'eth'
+AND canonical = true;
+`,
+ result: [
+ {
+ id: "11155111-0xb6fb46e1458915dd828633d91e1df8e4c3f2d4dd-0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae",
+ type: "ENSv1Domain",
+ canonical_name: "eth",
+ canonical_node: "0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae",
+ owner_id: "0xa51c9e6efe589407c72984e93b45e35a71a398ec",
+ },
+ {
+ id: "11155111-0x835f0b284e78cd3f358bcf6cba3b53809f09b79e-35894389512221139346028120028875095598761990588366713962827482865183915769856",
+ type: "ENSv2Domain",
+ canonical_name: "eth",
+ canonical_node: "0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae",
+ owner_id: "0xffffffffff52d316b7bd028358089bc8066b8f80",
+ },
+ ],
+ resultNote,
+ },
+ sdk: {
+ codeSnippet: `import { and, eq } from "drizzle-orm";
+
+const name = "eth";
+
+const domains = await ensDb
+ .select({
+ id: ensIndexerSchema.domain.id,
+ type: ensIndexerSchema.domain.type,
+ canonicalName: ensIndexerSchema.domain.canonicalName,
+ canonicalNode: ensIndexerSchema.domain.canonicalNode,
+ ownerId: ensIndexerSchema.domain.ownerId,
+ })
+ .from(ensIndexerSchema.domain)
+ .where(
+ and(
+ eq(ensIndexerSchema.domain.canonicalName, name),
+ eq(ensIndexerSchema.domain.canonical, true)
+ )
+ );
+
+console.log(domains);`,
+ result: [
+ {
+ id: "11155111-0xb6fb46e1458915dd828633d91e1df8e4c3f2d4dd-0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae",
+ type: "ENSv1Domain",
+ canonicalName: "eth",
+ canonicalNode: "0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae",
+ ownerId: "0xa51c9e6efe589407c72984e93b45e35a71a398ec",
+ },
+ {
+ id: "11155111-0x835f0b284e78cd3f358bcf6cba3b53809f09b79e-35894389512221139346028120028875095598761990588366713962827482865183915769856",
+ type: "ENSv2Domain",
+ canonicalName: "eth",
+ canonicalNode: "0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae",
+ ownerId: "0xffffffffff52d316b7bd028358089bc8066b8f80",
+ },
+ ],
+ resultNote,
+ },
+} satisfies QueryExample;
diff --git a/docs/ensnode.io/src/data/unigraph-examples/domain-events.ts b/docs/ensnode.io/src/data/unigraph-examples/domain-events.ts
new file mode 100644
index 000000000..af585abed
--- /dev/null
+++ b/docs/ensnode.io/src/data/unigraph-examples/domain-events.ts
@@ -0,0 +1,133 @@
+import { outputSource } from "./utils";
+import type { QueryExample } from "./types";
+
+const resultNote = outputSource("V2 Sepolia");
+
+/**
+ * Example query for fetching recent events for a Domain by its canonical name.
+ */
+export const exampleDomainEvents = {
+ sql: {
+ codeSnippet: `SELECT
+ e.chain_id,
+ e.block_number,
+ e.transaction_hash,
+ e.log_index,
+ e.address as contract_address,
+ e.sender,
+ d.id as domain_id
+FROM "ensindexer_0".events e
+JOIN "ensindexer_0".domain_events de ON e.id = de.event_id
+JOIN "ensindexer_0".domains d ON de.domain_id = d.id
+WHERE d.canonical_name = 'wrapnation.eth'
+AND d.canonical = true
+ORDER BY e.block_number DESC, e.log_index DESC
+LIMIT 5;
+`,
+ result: [
+ {
+ chain_id: "11155111",
+ block_number: "10918673",
+ transaction_hash: "0xca5e111932f0b26e1d458c690c5dfe8b2b8165ee2a937c04e4021e93a71954e4",
+ log_index: 42,
+ contract_address: "0xb68e594a47fe057bd31e7a8229ffcfd85b2e28af",
+ sender: "0x801d2e48d378f161dba7ad7ad002ad557714c191",
+ domain_id:
+ "11155111-0x64c81210d0e580cfc7746f3fb910bf0e8f6378e1-68387108911874305622019956908914347119991166106996198835225265868637904830464",
+ },
+ {
+ chain_id: "11155111",
+ block_number: "10918673",
+ transaction_hash: "0xca5e111932f0b26e1d458c690c5dfe8b2b8165ee2a937c04e4021e93a71954e4",
+ log_index: 38,
+ contract_address: "0x64c81210d0e580cfc7746f3fb910bf0e8f6378e1",
+ sender: "0xb68e594a47fe057bd31e7a8229ffcfd85b2e28af",
+ domain_id:
+ "11155111-0x64c81210d0e580cfc7746f3fb910bf0e8f6378e1-68387108911874305622019956908914347119991166106996198835225265868637904830464",
+ },
+ {
+ chain_id: "11155111",
+ block_number: "10918673",
+ transaction_hash: "0xca5e111932f0b26e1d458c690c5dfe8b2b8165ee2a937c04e4021e93a71954e4",
+ log_index: 37,
+ contract_address: "0x64c81210d0e580cfc7746f3fb910bf0e8f6378e1",
+ sender: "0xb68e594a47fe057bd31e7a8229ffcfd85b2e28af",
+ domain_id:
+ "11155111-0x64c81210d0e580cfc7746f3fb910bf0e8f6378e1-68387108911874305622019956908914347119991166106996198835225265868637904830464",
+ },
+ ],
+ resultNote,
+ },
+ sdk: {
+ codeSnippet: `import { and, desc, eq } from "drizzle-orm";
+
+const name = "wrapnation.eth";
+const limit = 5;
+
+const domainEvents = await ensDb
+ .select({
+ chainId: ensIndexerSchema.event.chainId,
+ blockNumber: ensIndexerSchema.event.blockNumber,
+ transactionHash: ensIndexerSchema.event.transactionHash,
+ logIndex: ensIndexerSchema.event.logIndex,
+ contractAddress: ensIndexerSchema.event.address,
+ sender: ensIndexerSchema.event.sender,
+ domainId: ensIndexerSchema.domain.id,
+ })
+ .from(ensIndexerSchema.event)
+ .innerJoin(
+ ensIndexerSchema.domainEvent,
+ eq(ensIndexerSchema.event.id, ensIndexerSchema.domainEvent.eventId),
+ )
+ .innerJoin(
+ ensIndexerSchema.domain,
+ eq(ensIndexerSchema.domainEvent.domainId, ensIndexerSchema.domain.id),
+ )
+ .where(
+ and(
+ eq(ensIndexerSchema.domain.canonicalName, name),
+ eq(ensIndexerSchema.domain.canonical, true),
+ ),
+ )
+ .orderBy(
+ desc(ensIndexerSchema.event.blockNumber),
+ desc(ensIndexerSchema.event.logIndex),
+ )
+ .limit(limit);
+
+console.log(domainEvents);`,
+ result: [
+ {
+ chainId: 11155111,
+ blockNumber: "10918673",
+ transactionHash: "0xca5e111932f0b26e1d458c690c5dfe8b2b8165ee2a937c04e4021e93a71954e4",
+ logIndex: 42,
+ contractAddress: "0xb68e594a47fe057bd31e7a8229ffcfd85b2e28af",
+ sender: "0x801d2e48d378f161dba7ad7ad002ad557714c191",
+ domainId:
+ "11155111-0x64c81210d0e580cfc7746f3fb910bf0e8f6378e1-68387108911874305622019956908914347119991166106996198835225265868637904830464",
+ },
+ {
+ chainId: 11155111,
+ blockNumber: "10918673",
+ transactionHash: "0xca5e111932f0b26e1d458c690c5dfe8b2b8165ee2a937c04e4021e93a71954e4",
+ logIndex: 38,
+ contractAddress: "0x64c81210d0e580cfc7746f3fb910bf0e8f6378e1",
+ sender: "0xb68e594a47fe057bd31e7a8229ffcfd85b2e28af",
+ domainId:
+ "11155111-0x64c81210d0e580cfc7746f3fb910bf0e8f6378e1-68387108911874305622019956908914347119991166106996198835225265868637904830464",
+ },
+ {
+ chainId: 11155111,
+ blockNumber: "10918673",
+ transactionHash: "0xca5e111932f0b26e1d458c690c5dfe8b2b8165ee2a937c04e4021e93a71954e4",
+ logIndex: 37,
+ contractAddress: "0x64c81210d0e580cfc7746f3fb910bf0e8f6378e1",
+ sender: "0xb68e594a47fe057bd31e7a8229ffcfd85b2e28af",
+ domainId:
+ "11155111-0x64c81210d0e580cfc7746f3fb910bf0e8f6378e1-68387108911874305622019956908914347119991166106996198835225265868637904830464",
+ },
+ ],
+ resultNote,
+ },
+} satisfies QueryExample;
diff --git a/docs/ensnode.io/src/data/unigraph-examples/domains-fuzzy-search-by-name.ts b/docs/ensnode.io/src/data/unigraph-examples/domains-fuzzy-search-by-name.ts
new file mode 100644
index 000000000..1440e9f42
--- /dev/null
+++ b/docs/ensnode.io/src/data/unigraph-examples/domains-fuzzy-search-by-name.ts
@@ -0,0 +1,108 @@
+import { outputSource } from "./utils";
+import type { QueryExample } from "./types";
+
+const resultNote = outputSource("V2 Sepolia");
+
+/**
+ * Example query for fetching Domains by a fuzzy search on their canonical name.
+ */
+export const exampleDomainsFuzzySearchByName = {
+ sql: {
+ codeSnippet: `SELECT
+ type,
+ canonical_name,
+ canonical_node,
+ owner_id,
+ similarity(canonical_name, 'reverse') as name_similarity,
+ id
+FROM "ensindexer_0".domains
+WHERE __canonicalNamePrefix % 'reverse'
+AND canonical = true
+ORDER BY name_similarity DESC
+LIMIT 5;
+`,
+ result: [
+ {
+ type: "ENSv1Domain",
+ canonical_name: "reverse",
+ canonical_node: "0xa097f6721ce401e757d1223a763fef49b8b5f90bb18567ddb86fd205dff71d34",
+ owner_id: "0xffffffffff52d316b7bd028358089bc8066b8f80",
+ name_similarity: 1,
+ id: "11155111-0xb6fb46e1458915dd828633d91e1df8e4c3f2d4dd-0xa097f6721ce401e757d1223a763fef49b8b5f90bb18567ddb86fd205dff71d34",
+ },
+ {
+ type: "ENSv2Domain",
+ canonical_name: "reverse",
+ canonical_node: "0xa097f6721ce401e757d1223a763fef49b8b5f90bb18567ddb86fd205dff71d34",
+ owner_id: "0xffffffffff52d316b7bd028358089bc8066b8f80",
+ name_similarity: 1,
+ id: "11155111-0x835f0b284e78cd3f358bcf6cba3b53809f09b79e-100753657518907091865523951670693454610893379027273088370152078482136467767296",
+ },
+ {
+ type: "ENSv1Domain",
+ canonical_name: "addr.reverse",
+ canonical_node: "0x91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e2",
+ owner_id: "0x26e5e80e8f36607ef401443fb34eea363c86e8f7",
+ name_similarity: 0.61538464,
+ id: "11155111-0xb6fb46e1458915dd828633d91e1df8e4c3f2d4dd-0x91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e2",
+ },
+ ],
+ resultNote,
+ },
+ sdk: {
+ codeSnippet: `import { and, eq, sql } from "drizzle-orm";
+
+const q = "vitalik";
+const limit = 5;
+
+const domains = await ensDb
+ .select({
+ type: ensIndexerSchema.domain.type,
+ canonicalName: ensIndexerSchema.domain.canonicalName,
+ canonicalNode: ensIndexerSchema.domain.canonicalNode,
+ ownerId: ensIndexerSchema.domain.ownerId,
+ nameSimilarity: sql\`similarity(\${ensIndexerSchema.domain.canonicalName}, \${q})\`.as(
+ "name_similarity",
+ ),
+ id: ensIndexerSchema.domain.id,
+ })
+ .from(ensIndexerSchema.domain)
+ .where(
+ and(
+ sql\`\${ensIndexerSchema.domain.__canonicalNamePrefix} % \${q}\`,
+ eq(ensIndexerSchema.domain.canonical, true),
+ ),
+ )
+ .orderBy(sql\`name_similarity DESC\`)
+ .limit(limit);
+
+console.log(domains);`,
+ result: [
+ {
+ type: "ENSv1Domain",
+ canonicalName: "reverse",
+ canonicalNode: "0xa097f6721ce401e757d1223a763fef49b8b5f90bb18567ddb86fd205dff71d34",
+ ownerId: "0xffffffffff52d316b7bd028358089bc8066b8f80",
+ nameSimilarity: 1,
+ id: "11155111-0xb6fb46e1458915dd828633d91e1df8e4c3f2d4dd-0xa097f6721ce401e757d1223a763fef49b8b5f90bb18567ddb86fd205dff71d34",
+ },
+ {
+ type: "ENSv2Domain",
+ canonicalName: "reverse",
+ canonicalNode: "0xa097f6721ce401e757d1223a763fef49b8b5f90bb18567ddb86fd205dff71d34",
+ ownerId: "0xffffffffff52d316b7bd028358089bc8066b8f80",
+ nameSimilarity: 1,
+ id: "11155111-0x835f0b284e78cd3f358bcf6cba3b53809f09b79e-100753657518907091865523951670693454610893379027273088370152078482136467767296",
+ },
+ {
+ type: "ENSv1Domain",
+ canonicalName: "addr.reverse",
+ canonicalNode: "0x91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e2",
+ ownerId: "0x26e5e80e8f36607ef401443fb34eea363c86e8f7",
+ nameSimilarity: 0.61538464,
+ id: "11155111-0xb6fb46e1458915dd828633d91e1df8e4c3f2d4dd-0x91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e2",
+ },
+ ],
+ resultNote,
+ },
+} satisfies QueryExample;
diff --git a/docs/ensnode.io/src/data/unigraph-examples/expiring-registrations.ts b/docs/ensnode.io/src/data/unigraph-examples/expiring-registrations.ts
new file mode 100644
index 000000000..fbc3d15c5
--- /dev/null
+++ b/docs/ensnode.io/src/data/unigraph-examples/expiring-registrations.ts
@@ -0,0 +1,173 @@
+import { outputSource } from "./utils";
+import type { QueryExample } from "./types";
+
+const resultNote = outputSource("Alpha Sepolia");
+
+/**
+ * Example query for fetching ENS registrations that are expiring soon.
+ */
+export const exampleExpiringRegistrations = {
+ sql: {
+ codeSnippet: `SELECT
+ d.canonical_name,
+ r.start,
+ r.expiry,
+ r.grace_period,
+ d.owner_id,
+ d.id as domain_id
+FROM "ensindexer_0".registrations r
+JOIN "ensindexer_0".latest_registration_index lri
+ ON r.domain_id = lri.domain_id
+ AND r.registration_index = lri.registration_index
+JOIN "ensindexer_0".domains d ON r.domain_id = d.id
+WHERE r.expiry >= EXTRACT(EPOCH FROM NOW())
+ AND r.expiry <= EXTRACT(EPOCH FROM NOW() + INTERVAL '3 days')
+ AND d.canonical = true
+ORDER BY r.expiry ASC
+LIMIT 5;
+`,
+ result: [
+ {
+ canonical_name: "block-land.eth",
+ start: "1717602456",
+ expiry: "1780674456",
+ grace_period: "7776000",
+ owner_id: "0x95e488ed0d3497f8cf2392e35c9eb81812ef863c",
+ domain_id:
+ "11155111-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x4263eab7cb93cb3161f613e59357fce5de6646c9dab3682c388938231ca16fe6",
+ },
+ {
+ canonical_name: "hagemz.eth",
+ start: "1749139932",
+ expiry: "1780675932",
+ grace_period: "7776000",
+ owner_id: "0xeb4bde48fb4ad1ab104eb1ef978fdd24e11d6a28",
+ domain_id:
+ "11155111-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x7886dc1e5b637005edf606d9e0f5cee78bd86a57e1378e1c76c3fa7557847659",
+ },
+ {
+ canonical_name: "leogomez.eth",
+ start: "1749152664",
+ expiry: "1780688664",
+ grace_period: "7776000",
+ owner_id: "0x2f7970674b6410f90b8bc43d8188ef35ab3f1a9b",
+ domain_id:
+ "11155111-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x6c577a69aa94e39ee0ff1beedbd3385f405506bc35d88f47284056c1ceba5759",
+ },
+ {
+ canonical_name: "ilanklein.eth",
+ start: "1749156780",
+ expiry: "1780692780",
+ grace_period: "7776000",
+ owner_id: "0x99969df2da9bf780cfd62d7cc22f77e5bdb332df",
+ domain_id:
+ "11155111-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x94877f55b294b34b0ac4952ad746f1c163a7e1aba16c41d113c558cd4f2bdff5",
+ },
+ {
+ canonical_name: "iwms.eth",
+ start: "1749157272",
+ expiry: "1780693272",
+ grace_period: "7776000",
+ owner_id: "0xa098364308d3e400e2f1199675ac765adac4810f",
+ domain_id:
+ "11155111-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x13403c49bb9d168c7f18b830b5dd86f562e3e203fe2fc545927e5f609e3e6417",
+ },
+ ],
+ resultNote,
+ },
+ sdk: {
+ codeSnippet: `import { and, asc, eq, gte, lte, sql } from "drizzle-orm";
+
+const limit = 5;
+
+const expiringRegistrations = await ensDb
+ .select({
+ canonicalName: ensIndexerSchema.domain.canonicalName,
+ expiry: ensIndexerSchema.registration.expiry,
+ start: ensIndexerSchema.registration.start,
+ gracePeriod: ensIndexerSchema.registration.gracePeriod,
+ ownerId: ensIndexerSchema.domain.ownerId,
+ domainId: ensIndexerSchema.domain.id,
+ })
+ .from(ensIndexerSchema.registration)
+ .innerJoin(
+ ensIndexerSchema.latestRegistrationIndex,
+ and(
+ eq(
+ ensIndexerSchema.registration.domainId,
+ ensIndexerSchema.latestRegistrationIndex.domainId,
+ ),
+ eq(
+ ensIndexerSchema.registration.registrationIndex,
+ ensIndexerSchema.latestRegistrationIndex.registrationIndex,
+ ),
+ ),
+ )
+ .innerJoin(
+ ensIndexerSchema.domain,
+ eq(ensIndexerSchema.registration.domainId, ensIndexerSchema.domain.id),
+ )
+ .where(
+ and(
+ gte(ensIndexerSchema.registration.expiry, sql\`EXTRACT(EPOCH FROM NOW())\`),
+ lte(
+ ensIndexerSchema.registration.expiry,
+ sql\`EXTRACT(EPOCH FROM NOW() + INTERVAL '3 days')\`,
+ ),
+ eq(ensIndexerSchema.domain.canonical, true),
+ ),
+ )
+ .orderBy(asc(ensIndexerSchema.registration.expiry))
+ .limit(limit);
+
+console.log(expiringRegistrations);`,
+ result: [
+ {
+ canonicalName: "block-land.eth",
+ expiry: "1780674456",
+ start: "1717602456",
+ gracePeriod: "7776000",
+ ownerId: "0x95e488ed0d3497f8cf2392e35c9eb81812ef863c",
+ domainId:
+ "11155111-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x4263eab7cb93cb3161f613e59357fce5de6646c9dab3682c388938231ca16fe6",
+ },
+ {
+ canonicalName: "hagemz.eth",
+ expiry: "1780675932",
+ start: "1749139932",
+ gracePeriod: "7776000",
+ ownerId: "0xeb4bde48fb4ad1ab104eb1ef978fdd24e11d6a28",
+ domainId:
+ "11155111-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x7886dc1e5b637005edf606d9e0f5cee78bd86a57e1378e1c76c3fa7557847659",
+ },
+ {
+ canonicalName: "leogomez.eth",
+ expiry: "1780688664",
+ start: "1749152664",
+ gracePeriod: "7776000",
+ ownerId: "0x2f7970674b6410f90b8bc43d8188ef35ab3f1a9b",
+ domainId:
+ "11155111-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x6c577a69aa94e39ee0ff1beedbd3385f405506bc35d88f47284056c1ceba5759",
+ },
+ {
+ canonicalName: "ilanklein.eth",
+ expiry: "1780692780",
+ start: "1749156780",
+ gracePeriod: "7776000",
+ ownerId: "0x99969df2da9bf780cfd62d7cc22f77e5bdb332df",
+ domainId:
+ "11155111-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x94877f55b294b34b0ac4952ad746f1c163a7e1aba16c41d113c558cd4f2bdff5",
+ },
+ {
+ canonicalName: "iwms.eth",
+ expiry: "1780693272",
+ start: "1749157272",
+ gracePeriod: "7776000",
+ ownerId: "0xa098364308d3e400e2f1199675ac765adac4810f",
+ domainId:
+ "11155111-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x13403c49bb9d168c7f18b830b5dd86f562e3e203fe2fc545927e5f609e3e6417",
+ },
+ ],
+ resultNote,
+ },
+} satisfies QueryExample;
diff --git a/docs/ensnode.io/src/data/unigraph-examples/indexing-status.ts b/docs/ensnode.io/src/data/unigraph-examples/indexing-status.ts
new file mode 100644
index 000000000..a8aee98fe
--- /dev/null
+++ b/docs/ensnode.io/src/data/unigraph-examples/indexing-status.ts
@@ -0,0 +1,137 @@
+import { outputSource } from "@data/unigraph-examples/utils";
+import type { QueryExample } from "./types";
+
+const resultNote = outputSource("Alpha");
+
+const indexingMetadataContextPartial = {
+ indexingStatus: {
+ strategy: "omnichain",
+ snapshotTime: 1779795066,
+ omnichainSnapshot: {
+ chains: {
+ 1: {
+ config: {
+ rangeType: "left-bounded",
+ startBlock: {
+ number: 3327417,
+ timestamp: 1489165544,
+ },
+ },
+ chainStatus: "chain-backfill",
+ backfillEndBlock: {
+ number: 25171597,
+ timestamp: 1779703391,
+ },
+ latestIndexedBlock: {
+ number: 21224717,
+ timestamp: 1732054691,
+ },
+ },
+ 10: {
+ config: {
+ rangeType: "left-bounded",
+ startBlock: {
+ number: 110393959,
+ timestamp: 1696386695,
+ },
+ },
+ chainStatus: "chain-backfill",
+ backfillEndBlock: {
+ number: 152052671,
+ timestamp: 1779704119,
+ },
+ latestIndexedBlock: {
+ number: 128226309,
+ timestamp: 1732051395,
+ },
+ },
+ 8453: {
+ config: {
+ rangeType: "left-bounded",
+ startBlock: {
+ number: 17522624,
+ timestamp: 1721834595,
+ },
+ },
+ chainStatus: "chain-backfill",
+ backfillEndBlock: {
+ number: 46457386,
+ timestamp: 1779704119,
+ },
+ latestIndexedBlock: {
+ number: 22632818,
+ timestamp: 1732054983,
+ },
+ },
+ 42161: {
+ config: {
+ rangeType: "left-bounded",
+ startBlock: {
+ number: 349263357,
+ timestamp: 1750406457,
+ },
+ },
+ chainStatus: "chain-queued",
+ },
+ 59144: {
+ config: {
+ rangeType: "left-bounded",
+ startBlock: {
+ number: 6682888,
+ timestamp: 1720768992,
+ },
+ },
+ chainStatus: "chain-backfill",
+ backfillEndBlock: {
+ number: 30774477,
+ timestamp: 1779703911,
+ },
+ latestIndexedBlock: {
+ number: 12280006,
+ timestamp: 1732054967,
+ },
+ },
+ 534352: {
+ config: {
+ rangeType: "left-bounded",
+ startBlock: {
+ number: 16604272,
+ timestamp: 1750406415,
+ },
+ },
+ chainStatus: "chain-queued",
+ },
+ },
+ omnichainStatus: "omnichain-backfill",
+ omnichainIndexingCursor: 1732054983,
+ },
+ slowestChainIndexingCursor: 1732054983,
+ },
+} as const;
+
+/**
+ * Example query for fetching the indexing status snapshot of an ENSDb Writer
+ */
+export const exampleIndexingStatus = {
+ sql: {
+ codeSnippet: `SELECT value -> 'indexingStatus' as indexing_status_snapshot
+FROM "ensnode".metadata
+WHERE ens_indexer_schema_name = 'ensindexer_0'
+AND key = 'indexing_metadata_context';
+`,
+ result: { indexing_status_snapshot: indexingMetadataContextPartial.indexingStatus },
+ resultNote,
+ },
+ sdk: {
+ codeSnippet: `import { IndexingMetadataContextStatusCodes } from "@ensnode/ensdb-sdk";
+
+const indexingMetadataContext = await ensDbReader.getIndexingMetadataContext();
+
+if (indexingMetadataContext.statusCode === IndexingMetadataContextStatusCodes.Initialized) {
+ const { indexingStatus } = indexingMetadataContext;
+ console.log({ indexingStatus });
+}`,
+ result: { indexingStatus: indexingMetadataContextPartial.indexingStatus },
+ resultNote,
+ },
+} satisfies QueryExample;
diff --git a/docs/ensnode.io/src/data/unigraph-examples/latest-registrations.ts b/docs/ensnode.io/src/data/unigraph-examples/latest-registrations.ts
new file mode 100644
index 000000000..1e21d43da
--- /dev/null
+++ b/docs/ensnode.io/src/data/unigraph-examples/latest-registrations.ts
@@ -0,0 +1,188 @@
+import { outputSource } from "./utils";
+import type { QueryExample } from "./types";
+
+const resultNote = outputSource("Alpha Sepolia");
+
+/**
+ * Example query for fetching the latest registrations across all Domains.
+ */
+export const exampleLatestRegistrations = {
+ sql: {
+ codeSnippet: `SELECT
+ d.canonical_name,
+ r.start,
+ r.expiry,
+ r.grace_period,
+ r.base,
+ r.premium,
+ r.type as registration_type,
+ d.owner_id,
+ d.id as domain_id
+FROM "ensindexer_0".registrations r
+JOIN "ensindexer_0".latest_registration_index lri
+ ON r.domain_id = lri.domain_id
+ AND r.registration_index = lri.registration_index
+JOIN "ensindexer_0".domains d ON r.domain_id = d.id
+WHERE r.start <= EXTRACT(EPOCH FROM NOW())
+ AND d.canonical = true
+ AND r.type <> 'NameWrapper'
+ORDER BY r.start DESC
+LIMIT 5;
+`,
+ result: [
+ {
+ canonical_name: "[67f53c740a0051f85075dc2383fb83a7b48d2984fc9ed9db56b334ca96d1d309].eth",
+ start: "1779816216",
+ expiry: "1811352216",
+ grace_period: "7776000",
+ base: "3125000000003490",
+ premium: "0",
+ registration_type: "BaseRegistrar",
+ owner_id: "0x205d2686da3bf33f64c17f21462c51b5ead462cf",
+ domain_id:
+ "11155111-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x085bfc7f3695efa2e9d3f9717214d85474f40b4b3ef902b67d2bb49654679fa1",
+ },
+ {
+ canonical_name: "coolorg.eth",
+ start: "1779794160",
+ expiry: "1811330160",
+ grace_period: "7776000",
+ base: "3125000000003490",
+ premium: "0",
+ registration_type: "BaseRegistrar",
+ owner_id: "0x5f71c6074141d41d0e769689dc9830388a5c7e3e",
+ domain_id:
+ "11155111-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0xe2a76df5554592c08c28946f750aad17d0c2bb3553c6dd2f0298e0f2fe873be3",
+ },
+ {
+ canonical_name: "[1d79e56219bd305bbd3fa8ab125997beceebe63b8f6e12d0b6cb956e955549ca].eth",
+ start: "1779785856",
+ expiry: "1906016256",
+ grace_period: "7776000",
+ base: "12508561643849586",
+ premium: "0",
+ registration_type: "BaseRegistrar",
+ owner_id: "0x07a811c0bd3f46733822df66d7e2d723e6f73fd6",
+ domain_id:
+ "11155111-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x8f9e9956842380910d836aa4ac85bc50bee0999824ea8b54412d02bc56d57c6c",
+ },
+ {
+ canonical_name: "kevin-af.eth",
+ start: "1779768924",
+ expiry: "1874463324",
+ grace_period: "7776000",
+ base: "9383561643846096",
+ premium: "0",
+ registration_type: "BaseRegistrar",
+ owner_id: "0x6a89280251f72918b6b143817201008b3d99d96e",
+ domain_id:
+ "11155111-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x49c87057b1dbe6a6bdfdcf9cc9b2bc12544bc3cd9fd01aa6ea8efb7dab89ca7e",
+ },
+ {
+ canonical_name: "executor1.eth",
+ start: "1779743592",
+ expiry: "1937509992",
+ grace_period: "7776000",
+ base: "15633561643853076",
+ premium: "0",
+ registration_type: "BaseRegistrar",
+ owner_id: "0xbb0274908a353d7c37a97ea1ea099352ee39734e",
+ domain_id:
+ "11155111-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x56fc11b057812d300b43fd13136ee7e656fa9081e5a3063ed011224302b3658f",
+ },
+ ],
+ resultNote,
+ },
+ sdk: {
+ codeSnippet: `import { and, desc, eq, ne, lte, sql } from "drizzle-orm";
+
+const limit = 5;
+
+const recentRegistrations = await ensDb
+ .select({
+ canonicalName: ensIndexerSchema.domain.canonicalName,
+ expiry: ensIndexerSchema.registration.expiry,
+ start: ensIndexerSchema.registration.start,
+ registrationType: ensIndexerSchema.registration.type,
+ ownerId: ensIndexerSchema.domain.ownerId,
+ domainId: ensIndexerSchema.domain.id,
+ })
+ .from(ensIndexerSchema.registration)
+ .innerJoin(
+ ensIndexerSchema.latestRegistrationIndex,
+ and(
+ eq(
+ ensIndexerSchema.registration.domainId,
+ ensIndexerSchema.latestRegistrationIndex.domainId,
+ ),
+ eq(
+ ensIndexerSchema.registration.registrationIndex,
+ ensIndexerSchema.latestRegistrationIndex.registrationIndex,
+ ),
+ ),
+ )
+ .innerJoin(
+ ensIndexerSchema.domain,
+ eq(ensIndexerSchema.registration.domainId, ensIndexerSchema.domain.id),
+ )
+ .where(
+ and(
+ lte(ensIndexerSchema.registration.start, sql\`EXTRACT(EPOCH FROM NOW())\`),
+ eq(ensIndexerSchema.domain.canonical, true),
+ ne(ensIndexerSchema.registration.type, "NameWrapper"),
+ ),
+ )
+ .orderBy(desc(ensIndexerSchema.registration.start))
+ .limit(limit);
+
+console.log(recentRegistrations);`,
+ result: [
+ {
+ canonicalName: "[67f53c740a0051f85075dc2383fb83a7b48d2984fc9ed9db56b334ca96d1d309].eth",
+ expiry: "1811352216",
+ start: "1779816216",
+ registrationType: "BaseRegistrar",
+ ownerId: "0x205d2686da3bf33f64c17f21462c51b5ead462cf",
+ domainId:
+ "11155111-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x085bfc7f3695efa2e9d3f9717214d85474f40b4b3ef902b67d2bb49654679fa1",
+ },
+ {
+ canonicalName: "coolorg.eth",
+ expiry: "1811330160",
+ start: "1779794160",
+ registrationType: "BaseRegistrar",
+ ownerId: "0x5f71c6074141d41d0e769689dc9830388a5c7e3e",
+ domainId:
+ "11155111-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0xe2a76df5554592c08c28946f750aad17d0c2bb3553c6dd2f0298e0f2fe873be3",
+ },
+ {
+ canonicalName: "[1d79e56219bd305bbd3fa8ab125997beceebe63b8f6e12d0b6cb956e955549ca].eth",
+ expiry: "1906016256",
+ start: "1779785856",
+ registrationType: "BaseRegistrar",
+ ownerId: "0x07a811c0bd3f46733822df66d7e2d723e6f73fd6",
+ domainId:
+ "11155111-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x8f9e9956842380910d836aa4ac85bc50bee0999824ea8b54412d02bc56d57c6c",
+ },
+ {
+ canonicalName: "kevin-af.eth",
+ expiry: "1874463324",
+ start: "1779768924",
+ registrationType: "BaseRegistrar",
+ ownerId: "0x6a89280251f72918b6b143817201008b3d99d96e",
+ domainId:
+ "11155111-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x49c87057b1dbe6a6bdfdcf9cc9b2bc12544bc3cd9fd01aa6ea8efb7dab89ca7e",
+ },
+ {
+ canonicalName: "executor1.eth",
+ expiry: "1937509992",
+ start: "1779743592",
+ registrationType: "BaseRegistrar",
+ ownerId: "0xbb0274908a353d7c37a97ea1ea099352ee39734e",
+ domainId:
+ "11155111-0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e-0x56fc11b057812d300b43fd13136ee7e656fa9081e5a3063ed011224302b3658f",
+ },
+ ],
+ resultNote,
+ },
+} satisfies QueryExample;
diff --git a/docs/ensnode.io/src/data/unigraph-examples/subdomains-by-parent-name.ts b/docs/ensnode.io/src/data/unigraph-examples/subdomains-by-parent-name.ts
new file mode 100644
index 000000000..b3b2a28d6
--- /dev/null
+++ b/docs/ensnode.io/src/data/unigraph-examples/subdomains-by-parent-name.ts
@@ -0,0 +1,138 @@
+import { outputSource } from "./utils";
+import type { QueryExample } from "./types";
+
+const resultNote = outputSource("V2 Sepolia");
+
+/**
+ * Example query for fetching subdomains by their canonical name of the parent domain.
+ */
+export const exampleSubdomainsByParentName = {
+ sql: {
+ codeSnippet: `WITH parent AS (
+ SELECT subregistry_id
+ FROM "ensindexer_0".domains
+ WHERE canonical_name = 'eth'
+ AND canonical = true
+)
+SELECT
+ d.type,
+ d.canonical_name,
+ d.canonical_node,
+ d.id
+FROM "ensindexer_0".domains d
+JOIN parent p ON d.registry_id = p.subregistry_id
+WHERE d.canonical = true
+ORDER BY d.canonical_name
+LIMIT 5;
+`,
+ result: [
+ {
+ type: "ENSv1Domain",
+ canonical_name: "[52602a50858115661619fb28cf543ee766c182e0be6743c72d5bd674b3d12686].eth",
+ canonical_node: "0xe91ce3506cd47457c2b3f04c2736875ca1d17ed74bf1a328a7e64cca5ae8c94b",
+ id: "11155111-0xb6fb46e1458915dd828633d91e1df8e4c3f2d4dd-0xe91ce3506cd47457c2b3f04c2736875ca1d17ed74bf1a328a7e64cca5ae8c94b",
+ },
+ {
+ type: "ENSv1Domain",
+ canonical_name: "[d90db363b8bc1371f7d738d264ff7294bfc5636f907c467adf68321a3c6d8188].eth",
+ canonical_node: "0x08c0f01c419a8971af6b3eefe2a8bba1556cccf1163df60b1cdbcab632c8ab48",
+ id: "11155111-0xb6fb46e1458915dd828633d91e1df8e4c3f2d4dd-0x08c0f01c419a8971af6b3eefe2a8bba1556cccf1163df60b1cdbcab632c8ab48",
+ },
+ {
+ type: "ENSv2Domain",
+ canonical_name: "katrenpadu.eth",
+ canonical_node: "0xf8ae81127bcd7ff99828b3dbd982a943d6dd961ee3f1a6ca707aa0eea913328e",
+ id: "11155111-0x64c81210d0e580cfc7746f3fb910bf0e8f6378e1-112554048520345018269255786667391470421317806528110367240542760381540064034816",
+ },
+ {
+ type: "ENSv2Domain",
+ canonical_name: "roppp.eth",
+ canonical_node: "0x39095c3dfb872d6441c95547f88591e7fb97014eef30cabe3df12a9b2a64dbe8",
+ id: "11155111-0x64c81210d0e580cfc7746f3fb910bf0e8f6378e1-88275407146030613359050872632052369891139576190404928761656352489271755538432",
+ },
+ {
+ type: "ENSv1Domain",
+ canonical_name: "sfmpfv44d0mig.eth",
+ canonical_node: "0x9b365136312d7ee6e232e3c98e459bc8667ec818c47fbbc55bb5e23d0a21e8cc",
+ id: "11155111-0xb6fb46e1458915dd828633d91e1df8e4c3f2d4dd-0x9b365136312d7ee6e232e3c98e459bc8667ec818c47fbbc55bb5e23d0a21e8cc",
+ },
+ ],
+ resultNote,
+ },
+ sdk: {
+ codeSnippet: `import { and, eq, inArray, asc } from "drizzle-orm";
+
+const name = "eth";
+const limit = 5;
+
+// Two-step:
+// 1) find parent domains
+// 2) query children by each parent domain's subregistryId.
+const parentDomains = await ensDb
+ .select({ subregistryId: ensIndexerSchema.domain.subregistryId })
+ .from(ensIndexerSchema.domain)
+ .where(
+ and(
+ eq(ensIndexerSchema.domain.canonicalName, name),
+ eq(ensIndexerSchema.domain.canonical, true),
+ ),
+ );
+
+if (parentDomains.length > 0) {
+ const subdomains = await ensDb
+ .select({
+ type: ensIndexerSchema.domain.type,
+ canonicalName: ensIndexerSchema.domain.canonicalName,
+ canonicalNode: ensIndexerSchema.domain.canonicalNode,
+ id: ensIndexerSchema.domain.id,
+ })
+ .from(ensIndexerSchema.domain)
+ .where(
+ and(
+ inArray(
+ ensIndexerSchema.domain.registryId,
+ parentDomains.map((d) => d.subregistryId),
+ ),
+ eq(ensIndexerSchema.domain.canonical, true),
+ ),
+ )
+ .orderBy(asc(ensIndexerSchema.domain.__canonicalNamePrefix))
+ .limit(limit);
+
+ console.log(subdomains);
+}`,
+ result: [
+ {
+ type: "ENSv1Domain",
+ canonicalName: "[52602a50858115661619fb28cf543ee766c182e0be6743c72d5bd674b3d12686].eth",
+ canonicalNode: "0xe91ce3506cd47457c2b3f04c2736875ca1d17ed74bf1a328a7e64cca5ae8c94b",
+ id: "11155111-0xb6fb46e1458915dd828633d91e1df8e4c3f2d4dd-0xe91ce3506cd47457c2b3f04c2736875ca1d17ed74bf1a328a7e64cca5ae8c94b",
+ },
+ {
+ type: "ENSv1Domain",
+ canonicalName: "[d90db363b8bc1371f7d738d264ff7294bfc5636f907c467adf68321a3c6d8188].eth",
+ canonicalNode: "0x08c0f01c419a8971af6b3eefe2a8bba1556cccf1163df60b1cdbcab632c8ab48",
+ id: "11155111-0xb6fb46e1458915dd828633d91e1df8e4c3f2d4dd-0x08c0f01c419a8971af6b3eefe2a8bba1556cccf1163df60b1cdbcab632c8ab48",
+ },
+ {
+ type: "ENSv2Domain",
+ canonicalName: "katrenpadu.eth",
+ canonicalNode: "0xf8ae81127bcd7ff99828b3dbd982a943d6dd961ee3f1a6ca707aa0eea913328e",
+ id: "11155111-0x64c81210d0e580cfc7746f3fb910bf0e8f6378e1-112554048520345018269255786667391470421317806528110367240542760381540064034816",
+ },
+ {
+ type: "ENSv2Domain",
+ canonicalName: "roppp.eth",
+ canonicalNode: "0x39095c3dfb872d6441c95547f88591e7fb97014eef30cabe3df12a9b2a64dbe8",
+ id: "11155111-0x64c81210d0e580cfc7746f3fb910bf0e8f6378e1-88275407146030613359050872632052369891139576190404928761656352489271755538432",
+ },
+ {
+ type: "ENSv2Domain",
+ canonicalName: "sfmpfv44d0mig.eth",
+ canonicalNode: "0x9b365136312d7ee6e232e3c98e459bc8667ec818c47fbbc55bb5e23d0a21e8cc",
+ id: "11155111-0x64c81210d0e580cfc7746f3fb910bf0e8f6378e1-30078755955643454526763071980293195785165410039216352470119925106082295316480",
+ },
+ ],
+ resultNote,
+ },
+} satisfies QueryExample;
diff --git a/docs/ensnode.io/src/data/unigraph-examples/types.ts b/docs/ensnode.io/src/data/unigraph-examples/types.ts
new file mode 100644
index 000000000..56aebb586
--- /dev/null
+++ b/docs/ensnode.io/src/data/unigraph-examples/types.ts
@@ -0,0 +1,10 @@
+export interface CodeExample {
+ codeSnippet: string;
+ result: unknown;
+ resultNote?: string;
+}
+
+export interface QueryExample {
+ sql: CodeExample;
+ sdk: CodeExample;
+}
diff --git a/docs/ensnode.io/src/data/unigraph-examples/utils.ts b/docs/ensnode.io/src/data/unigraph-examples/utils.ts
new file mode 100644
index 000000000..9935d4e66
--- /dev/null
+++ b/docs/ensnode.io/src/data/unigraph-examples/utils.ts
@@ -0,0 +1,2 @@
+export const outputSource = (source: "V2 Sepolia" | "Alpha" | "Alpha Sepolia") =>
+ `Output matches a point in time snapshot of ENSDb result from our "${source}" Hosted ENSNode instance. Live output depends on the configuration of your ENSNode instance and also changes that may have happened in ENS since this point in time snapshot example response was captured.`;