Skip to content

Arkiv is a Web3 database. It stores your data as entities that you can query by indexed attributes, that your wallet owns, and that expire when you say so. You talk to it with the same tools you use for Ethereum: a wallet, a transaction, and a JSON-RPC endpoint.

For years, builders had to choose. Web2 is fast and convenient, until it locks you in, goes down, or shuts you out. Web3 hands you ownership, then makes you pay for it in speed, simplicity, and cost.

  • Live data is everywhere. DeFi, AI, gaming, and IoT all depend on queryable data. That data sits in centralized databases that nobody in the app owns.
  • Stuck in indexer hell. Builders re-index, or trust someone else’s server, for truth that is already written on-chain.
  • You pay forever. Most Web3 solutions never expire data from their query layer. It bloats over time, and you pay for it.
Web2Web3Arkiv
UXBattle testedBadGreat
IntegrityCentralizedTamper-proofTamper-proof
OwnershipFalse ownershipWallet-ownedWallet-owned
QueriesQueryableNot easily queryableQueryable
LifetimeTime-scopedPermanentTime-scoped

Arkiv is the layer for owned, queryable data, with Web3 guarantees.

Queryable

Filter and paginate records through indexed attributes with a Web2-like query language. No external indexer.

Time-scoped

Every entity has an expiration block. When it arrives, the entity leaves the query surface. You pay for the lifetime you choose.

Tamper-proof

Every write is a signed Ethereum transaction. State is committed with a keccak Merkle-Patricia trie, so any change is evident.

Wallet-owned

Only the owner wallet can update, extend, transfer, or delete an entity.

  1. Write. Store data as an entity with queryable custom attributes. The write is an Ethereum-style transaction to a DB-Chain.
  2. Own. Your wallet controls the entity. Update it, transfer it, or delete it.
  3. Query. Retrieve entities with Arkiv’s query language, served over JSON-RPC.
  4. Expire. Set an expiration time for your data. Extend it if it is still needed.

Arkiv is an Ethereum-aligned DB-Chain. It looks and feels like a database: CRUD and indexed queries over RPC, with programmable expiration.

┌──────────────────────────────────────────────────────────┐
│ YOUR APP │
│ TypeScript SDK · JSON-RPC · any Ethereum wallet │
└───────────────┬──────────────────────────┬───────────────┘
│ eth_sendRawTransaction │ arkiv_query
▼ ▼
┌──────────────────────────────────────────────────────────┐
│ ARKIV DB-CHAIN │
│ Sequencer produces blocks (2 s block time) │
│ Arkiv DB engine replaces the EVM: entities, attributes, │
│ indexes, expiry, ownership │
│ State root: keccak-MPT, readable with eth_getProof │
│ Watchers replicate the chain and serve reads │
└───────────────┬──────────────────────────────────────────┘
│ GLM deposits (relayer)
▼
┌──────────────────────────────────────────────────────────┐
│ ETHEREUM │
│ Source of GLM. Arkiv commits its records here for │
│ durable archival, so data stays recoverable and │
│ tamper-proof even if every Arkiv node disappears. │
└──────────────────────────────────────────────────────────┘

A chain with a database engine instead of the EVM

Section titled “A chain with a database engine instead of the EVM”

A DB-Chain runs on an Ethereum execution client with the EVM interpreter removed. In its place sits the Arkiv DB engine. The engine validates, decodes, and applies database operations, and it prices them by the storage work they cause.

  • No smart contracts, by construction. A transaction is accepted only if its to address is a known Arkiv operation address. Every other transaction reverts. No bytecode is deployed, not even at genesis.
  • Ethereum’s dialect, kept. Transactions, receipts, logs, gas, and JSON-RPC all keep the Ethereum shape. Your wallet and your tooling already know how to talk to Arkiv.
  • Two RPC namespaces on one endpoint. eth_* for transactions, receipts, balances, and proofs. arkiv_* for queries and entity views.

You pay for data operations in GLM. On testnets, the faucet gives you test GLM.

An entity is a data record on Arkiv. It has:

  • Payload: the data (JSON, text, binary), up to 128 KiB, with a MIME content type.
  • Attributes: typed key-value pairs for querying.
  • Expiration block: every entity expires. Set it when you create the entity.

The protocol also keeps system attributes on every entity: $owner, $creator, $createdAt, $updatedAt, and $expiresAt. You can query them. You cannot set them.

SDK methodWhoWhat
createEntity()any funded walletCreate an entity with attributes and a lifetime
patchEntity()ownerSet or unset attributes, or replace the payload
extendEntity()ownerMove the expiration later. Never earlier
changeOwnership()ownerHand the entity to another wallet
deleteEntity()ownerRemove the entity at once

One transaction can carry many operations. They apply as one atomic batch. If one fails, none apply.

Entity keys are derived by the protocol from your wallet, a nonce, and a random salt. Nobody can guess your next key. You can compute it yourself before you send the transaction with predictEntityKey().

The type you give a value decides which query operators work on it. Typed helpers come from @arkiv-network/sdk/attr. A plain string needs no helper:

import { i32 } from "@arkiv-network/sdk/attr";
{ type: "note" } // str: eq() and startsWith()
{ priority: i32(5) } // i32, u64, u256, dec: eq() and range (gt, lt, gte, lte)
{ active: true } // bool, addr, key, bytes32: eq() only

Arkiv measures time in blocks. One block is 2 seconds. Build a lifetime with ExpirationTime and pass it as expires:

import { ExpirationTime } from "@arkiv-network/sdk";
ExpirationTime.fromHours(12)
ExpirationTime.fromDays(7)
ExpirationTime.atBlock(1_200_000n)

From the expiration block on, the entity is gone from every query and rejects every operation. There is no event for this. If you mirror Arkiv data off-chain, track $expiresAt yourself.

Start with a short lifetime to save on fees. Extend it later if you still need the data.

A query is a boolean expression. No SELECT, no WHERE:

type = str('note') AND priority > i32(3)

Operators: AND, OR, NOT, =, <, >, <=, >=, STARTSWITH. Tag every value with its type, except bare booleans and bare i32 numbers. Use * to match every entity. There is no != yet. Write NOT (attr = value).

Full syntax reference: Query syntax.

  • WalletClient (read/write): needs a private key or a wallet connection. Use it to create, patch, and delete entities.
  • PublicClient (read-only): needs no private key. Use it for queries. It is safe for frontend use.

The query builder of the SDK does more than basic filtering. Before you write a manual workaround, see what it already provides:

  • Field selection: fetch only the entity fields you need with select({ key: true, payload: true }). The result type narrows to exactly those fields.
  • Newest-first results: matching entities always come back newest first. To sort them differently, sort the results in JavaScript.
  • Pagination: page through results with hasNextPage() and next(). Each page holds up to 200 results.
  • Entity count: get a count without fetching entities. Call getEntityCount().
  • Owner and creator filters: use .ownedBy() and .createdBy() to filter by wallet.

Full reference: Querying Data

  • Temporary data storage: session data with automatic expiration, cross-device clipboards, cached API responses.
  • Events and analytics: application logs with cleanup, user activity tracking, temporary metrics.
  • Files and media: image metadata with expiration, document versioning, chunked file storage.
  • Full-stack applications: dashboards, collaborative tools, browser-based dApps with wallet signing.

No advanced blockchain knowledge required. Use the SDK to create and query your data like you would with a Web2 database.

  1. Install the TypeScript SDK and create your first entity.
  2. Get test GLM on Tiramisu.
  3. Teach your AI tools Arkiv with the agent skill and MCP server.