Alchemy
Our RPC provider of record, and — in one lending dApp only — the account-abstraction stack.
Dashboard: https://dashboard.alchemy.com · Docs: https://www.alchemy.com/docs
As an RPC provider (all projects)
ALCHEMY_API_KEY= # SECRET, server-side
NEXT_PUBLIC_ALCHEMY_API_KEY= # public — MUST be domain-restricted in the dashboard
https://base-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}
https://base-sepolia.g.alchemy.com/v2/${ALCHEMY_API_KEY}
https://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}
https://eth-sepolia.g.alchemy.com/v2/${ALCHEMY_API_KEY}
https://solana-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}
A NEXT_PUBLIC_ key ships to every browser. That is acceptable only with an
allowlist configured in the Alchemy dashboard (Apps → your app → Security → allowed
domains/referrers). Add every Vercel preview domain too, or previews break.
Prefer a server-side proxy route for anything sensitive or expensive — the browser
hits /api/rpc, which forwards with the secret key. That also lets you cache.
Never use https://mainnet.base.org in production. It rate-limits and the
failures are intermittent, which makes them expensive to debug.
Rate limits and CU
Alchemy bills compute units, not requests — eth_getLogs over a wide range costs far
more than eth_blockNumber. Two rules:
- Cap
getLogsranges to 10k blocks and page. Wider returns an error, not a truncated result. - Batch reads with multicall rather than N single calls. See
../ekx-viem-wagmi/SKILL.md.
Handle 429 with backoff:
const transport = http(RPC_URL, { retryCount: 3, retryDelay: 500, batch: true });
batch: true coalesces concurrent calls into one JSON-RPC batch — often the single
biggest CU reduction available.
Smart wallets / gas sponsorship
One lending dApp uses @alchemy/wallet-apis for ERC-4337 smart accounts with sponsored gas,
so LATAM SME borrowers never need to hold ETH.
NEXT_PUBLIC_ALCHEMY_POLICY_ID= # gas manager policy
NEXT_PUBLIC_ALCHEMY_POLICY_ID_ETH=
NEXT_PUBLIC_ALCHEMY_POLICY_ID_SEPOLIA=
A gas manager policy is created in the dashboard and defines who gets sponsored and how much: allowlisted contract addresses, per-user and global spend caps, expiry. Configure the caps before going anywhere near mainnet — an open policy is a faucet for anyone who finds the policy ID, which is public by construction.
Policies are per-chain. A multi-chain app carries one ID per chain for that reason; the wrong ID for the active chain fails with an unhelpful "policy not found".
Related: @privy-io/alchemy-migration exists for this — such a repo
moved from Privy's own smart wallets to Alchemy's. Expect both code paths to exist.
Other Alchemy APIs in use
- NFT API (
nft-cdn.alchemy.com) — token metadata and images without running an indexer. Used for NFT previews. - Token API — balances by owner. Cheaper than looping
balanceOf. - x402 (
x402.alchemy.com) — pay-per-request HTTP payments; see../ekx-x402/SKILL.md.
Gotchas
- Unrestricted public key. Restrict by domain, always.
getLogs> 10k blocks errors. Page it, or use a subgraph.- Per-chain policy IDs. Not interchangeable.
- CU exhaustion looks like a bug, not a bill — sudden intermittent read failures near month-end are worth checking against the dashboard.
- Free tier is shared per app, so a busy preview deploy can starve production. Separate apps per environment.