Query the Chain
Reading is the other half of building. Before you build a transaction you need UTXOs and protocol parameters; after you submit one you wait for confirmation; a dApp UI shows balances, datums, and delegation. All of it comes from querying the chain through a provider, so you don't have to run and index a node yourself.
The conceptual model (UTXOs, datums) is in Transactions and eUTXO; this page is the read-side how-to.
Choosing a provider
A provider is the data source your SDK talks to. Most SDKs support several behind one unified interface, so the query methods stay the same no matter which you pick:
| Provider | Hosting | API key | Rate limits |
|---|---|---|---|
| Blockfrost | Hosted | Required | Yes (free tier limited) |
| Maestro | Hosted | Required | Yes (free tier limited) |
| Koios | Hosted (community) or self-hosted | Optional | Yes (higher with a key) |
| Kupmios | Self-hosted (Ogmios + Kupo) | Not applicable | None (your own infra) |
Configure one when you make the client:
- Evolution
- Mesh
import { mainnet, Client } from "@evolution-sdk/evolution"
// Blockfrost (hosted)
const bf = Client.make(mainnet).withBlockfrost({
baseUrl: "https://cardano-mainnet.blockfrost.io/api/v0",
projectId: process.env.BLOCKFROST_PROJECT_ID!
})
// Kupmios (self-hosted Ogmios + Kupo)
const kupmios = Client.make(mainnet).withKupmios({
ogmiosUrl: "http://localhost:1337",
kupoUrl: "http://localhost:1442"
})
// Maestro (hosted)
const maestro = Client.make(mainnet).withMaestro({
baseUrl: "https://mainnet.gomaestro-api.org/v1",
apiKey: process.env.MAESTRO_API_KEY!
})
// Koios (community)
const koios = Client.make(mainnet).withKoios({ baseUrl: "https://api.koios.rest/api/v1" })
import { BlockfrostProvider, KoiosProvider, MaestroProvider, OgmiosProvider } from "@meshsdk/core"
// Blockfrost (hosted), network auto-detected from the key prefix
const bf = new BlockfrostProvider(process.env.BLOCKFROST_PROJECT_ID!)
// Koios (community), pass the network
const koios = new KoiosProvider("mainnet")
// Maestro (hosted)
const maestro = new MaestroProvider({ network: "Mainnet", apiKey: process.env.MAESTRO_API_KEY! })
// Ogmios (self-hosted; Mesh has no single "Kupmios", pair it with Kupo for indexed reads)
const ogmios = new OgmiosProvider("ws://localhost:1337")
In Mesh the read methods live on the provider (an IFetcher/ISubmitter), not on a unified client. You pass the provider to MeshTxBuilder and the wallet, and call its fetch* methods directly.
Use the matching network base URL for Preprod/Preview (e.g. https://cardano-preprod.blockfrost.io/api/v0). For a hosted Kupmios like Demeter, pass the API keys through the connection. With Evolution that is the headers option on withKupmios:
const client = Client.make(mainnet).withKupmios({
ogmiosUrl: "https://ogmios.demeter.run",
kupoUrl: "https://kupo.demeter.run",
headers: {
ogmiosHeader: { "dmtr-api-key": process.env.DEMETER_API_KEY! },
kupoHeader: { "dmtr-api-key": process.env.DEMETER_API_KEY! }
}
})
Mesh has no single Kupmios provider; pair OgmiosProvider with Kupo and pass the Demeter keys through each provider's connection options.
Because the interface is unified, switching provider (e.g. Blockfrost in dev, self-hosted Kupmios in prod) is a one-line change. The query calls stay the same. For setting up the provider infrastructure itself (Blockfrost projects, running your own node + Kupo + Ogmios, Demeter), see the API providers reference and production infrastructure.
A hosted provider sees every address you query and every transaction you submit, along with your IP. It's a third party in your data path, with rate limits and an uptime you don't control. Self-hosting (your own node + Kupo + Ogmios, or Kupmios) keeps that data private and removes the dependency, at the cost of running the infrastructure. Pick based on how sensitive your queries are and how much ops you want to own.