Vue Solana includes composables for common Solana read paths: balances, account info, program accounts, and signature status.
Use this guide when your app needs to read chain state without signing a transaction.
Parse Addresses
Framework-agnostic code can normalize a Solana address with parseAddress().
import { parseAddress } from "@vue-solana/core/address";
import { createSolanaClient } from "@vue-solana/core/kit";
const address = parseAddress("11111111111111111111111111111111");
if (address) {
const client = createSolanaClient({ cluster: "devnet" });
const { value: lamports } = await client.rpc.getBalance(address).send();
}
parseAddress() accepts an Address, address string, ref-like object, getter, null, or undefined. Invalid address strings throw INVALID_ADDRESS.
Read Balance in Vue
<script setup lang="ts">
import { computed, ref } from "vue";
import { useBalance } from "@vue-solana/vue/useBalance";
const address = ref("PASTE_A_SOLANA_ADDRESS");
const { balance, loading, error, refresh } = useBalance(address);
const errorMessage = computed(() => {
switch (error.value?.code) {
case "INVALID_ADDRESS":
return "Enter a valid Solana address.";
case "RPC_FAILURE":
return "Unable to load the balance.";
default:
return null;
}
});
</script>
<template>
<section>
<p>Lamports: {{ balance ?? "Unknown" }}</p>
<p v-if="loading">Loading...</p>
<p v-if="errorMessage">{{ errorMessage }}</p>
<button type="button" @click="refresh">Refresh</button>
</section>
</template>
Read Account Info
Use useAccountInfo() for a single account.
<script setup lang="ts">
import { ref } from "vue";
import { useAccountInfo } from "@vue-solana/vue/useAccountInfo";
const address = ref("PASTE_A_SOLANA_ADDRESS");
const { accountInfo, loading, error, refresh } = useAccountInfo(address, {
commitment: "confirmed",
});
</script>
The composable returns normalized account data (executable, lamports, owner, space, and decoded data bytes) and clears stale state when the address becomes null or invalid. Call refresh() to re-read the account on demand.
Read Program Accounts
Use useProgramAccounts() for accounts owned by a program id.
<script setup lang="ts">
import { ref } from "vue";
import { useProgramAccounts } from "@vue-solana/vue/useProgramAccounts";
const programId = ref("PASTE_A_SOLANA_PROGRAM_ID");
const { accounts, loading, error, refresh } = useProgramAccounts(programId, {
commitment: "confirmed",
filters: [{ dataSize: 165 }],
dataSlice: { offset: 0, length: 32 },
});
</script>
Warning: Program account scans can be expensive. Use narrow filters,
dataSlice, caching, pagination, indexing, or dedicated RPC infrastructure for production reads.
Read Signature Status
Use useSignatureStatus() to track a known transaction signature.
<script setup lang="ts">
import { ref } from "vue";
import { useSignatureStatus } from "@vue-solana/vue/useSignatureStatus";
const signature = ref("PASTE_A_TRANSACTION_SIGNATURE");
const { status, error, refresh, stopPolling } = useSignatureStatus(signature, {
pollIntervalMs: 2_000,
});
</script>
Use polling for short-lived progress UI. Avoid indefinite polling from high-traffic pages.
Nuxt Auto-Imports
Nuxt exposes the same read helpers as auto-imported composables:
useSolanaBalance()useSolanaAccountInfo()useSolanaProgramAccounts()useSolanaSignatureStatus()
<script setup lang="ts">
const address = ref("PASTE_A_SOLANA_ADDRESS");
const { balance, loading, error, refresh } = useSolanaBalance(address);
</script>
Nuxt composables can be called during SSR and return inert state until hydration provides the real client context. Trigger network refreshes from client lifecycle hooks or user actions when the data depends on browser-only context.
Null and Invalid Inputs
Read composables clear state without calling RPC when the address, program id, or signature is null.
Invalid address strings clear stale data, set error, and do not call the RPC method. Branch on error.value.code for user-facing messages; an unparseable address reports INVALID_ADDRESS.
Refresh And Error Semantics
useBalance, useAccountInfo, useProgramAccounts, useTokenAccounts, and useTokenBalance share one state machine, so they behave the same way in three cases that are easy to get wrong.
refresh() rejects; it does not resolve on failure. It resolves with the new value on success, with null when an input is empty, and rejects with a normalized SolanaError otherwise. A bare @click="refresh" is fine because Vue swallows the rejection, but hand-written code must handle it:
// No error state on a rejected promise, so this silently does nothing useful.
await refresh();
// Await it and report.
try {
await refresh();
} catch (cause) {
console.error(cause);
}
useRequest() is the exception: its refresh() resolves with the attempt result rather than rejecting.
Data drops back to its empty value when a read fails. A previously loaded balance does not stay on screen next to a fresh error — it reads as current data when it is not. Branch on error to decide what to render:
<template>
<UAlert v-if="error" color="error" variant="subtle" :title="errorMessage" />
<p v-else-if="loading">Loading…</p>
<p v-else>Lamports: {{ balance ?? "—" }}</p>
</template>
Read-only results in useTokenBalance. Its balance and decimals are computed refs derived from one read. Read them; assigning to them has no effect.
RPC Cost Checklist
- Prefer direct single-account reads when possible.
- Use filters for program account scans.
- Use
dataSlicewhen you only need part of account data. - Avoid broad scans from landing pages or every route navigation.
- Avoid aggressive polling intervals on public RPC endpoints.
- Cache or index data that many users will request repeatedly.