Skip to main content

JavaScript SDK v4

Use this guide to migrate an application from JavaScript SDK v3 to JavaScript SDK v4.

Install v4

Install v4 and its @solana/web3.js peer dependency:

npm install @bonfida/spl-name-service@^4 @solana/web3.js@^1.98.2

Import from the package root

Root and category-subpath imports are supported in v4. These migration examples use the package root:

import {
getPrimaryDomain,
getRecord,
getSnsDomainsForOwner,
Record,
resolve,
} from "@bonfida/spl-name-service";

Update domain inputs

Use the input form required by each API family instead of applying one transformation to every domain:

API familyv3 inputv4 input
High-level reads, including resolve and record readsTLD-less SNS name; some APIs also accepted .solFull name with a supported suffix, such as name.sns
Domain and record writesTLD-less SNS nameLowercase full .sns name; follow the API's top-level or subdomain constraint
Synchronous derivation and raw name-account helpersTLD-less or raw account inputTLD-less or raw account input, as documented for the helper

Do not append .sns to inputs for low-level helpers such as getSnsDomainKeySync, getRecordV1Key, or getRecordV2Key.

.sol resolution and reads

SNS-backed .sol resolution and reads pause automatically at finalized slot 452,825,395 to transition .sol domains to the SRS program; slot checks are not needed at the application level. SRS-backed .sol resolution will be enabled in a future SDK update.

Update resolution

The resolve call shape is unchanged, but the domain now needs a supported suffix.

v3
import { resolve } from "@bonfida/spl-name-service";

const owner = await resolve(connection, "name");
v4
import { resolve } from "@bonfida/spl-name-service";

const owner = await resolve(connection, "name.sns"); // Or use `safeResolve`.
New API: safeResolve

A new safeResolve API has been added, currently functioning identically to resolve. Once SRS-backed .sol resolution is enabled in a future update, safeResolve will only return an address if the .sol domain and the corresponding .sns domain resolve to the same address — throwing an error on mismatch.

This is intended as a short-term safety measure for the period immediately following SRS-backed .sol enablement. In the long term, .sns and .sol should be treated as separate namespaces, and integrations should use resolve instead.

Recommended alternative: rather than relying on safeResolve (which throws on mismatch), apps and wallets can implement custom logic to detect resolution mismatches and surface a warning or confirmation dialog to the user.

Update primary-domain lookup

Replace getFavoriteDomain with getPrimaryDomain. If the v3 application already uses the getPrimaryDomain alias, the call does not change.

const primary = await getPrimaryDomain(connection, wallet);

if (!primary.stale) {
console.log(`${primary.reverse}.sns`);
}

The result remains { domain, reverse, stale }. domain is the name-account public key, reverse is TLD-less, and stale is true when the wallet no longer owns the selected domain.

Update owner-domain lookup

Replace getDomainKeysWithReverses with getSnsDomainsForOwner:

v3
const domains = await getDomainKeysWithReverses(connection, wallet);
v4
const domains = await getSnsDomainsForOwner(connection, wallet);
const displayNames = domains.map(({ domain }) => `${domain}.sns`);

The result property pubKey is now named key, and entries without a valid reverse name are omitted. This lookup returns directly registry-owned top-level domains; use getSnsNftsForOwner separately for tokenized domains.

Update record reads

In v4, getRecord reads record V2 data and returns a structured RecordResult. A v3 call that used the V1 getRecord API must change both its domain input and result handling:

v3
const content = await getRecord(connection, "name", Record.Url, true);
v4
const result = await getRecord(connection, "name.sns", Record.Url, {
deserialize: true,
});

console.log(result.deserializedContent);

Use result.verified.staleness and, when present, result.verified.roa to evaluate the record's verification status. Rename getRecordV2 to getRecord, and rename getRecords or getMultipleRecordsV2 to getMultipleRecords. Batch results preserve request order and use undefined for records that do not exist.

Update common write APIs

v4 uses .sns names for string-based high-level writes and consolidates common instruction builders:

v3v4Required change
registerDomainNameV2registerDomainPass a full top-level .sns name and remove the Connection argument
registerWithNftregisterDomainWithNftPass a full top-level .sns name; remove nftMetadata and masterEdition
registerFavoritesetPrimaryDomainRename the call; the name-account public key argument is unchanged
transferNameOwnershiptransferDomainPass a full top-level .sns name and remove the class, parent, and parent-owner arguments
createRecordInstruction or createRecordV2InstructioncreateRecordPass a full .sns domain and use the consolidated signature
updateRecordInstruction or updateRecordV2InstructionupdateRecordPass a full .sns domain and use the consolidated signature
deleteRecordV2deleteRecordPass a full .sns domain

These helpers return one or more TransactionInstruction values. The application remains responsible for adding them to a transaction, collecting the required signatures, and submitting it.

Verify the migration

  • Replace renamed imports and call sites.
  • Resolve a known domain with TLD suffix (name.sns/name.sol).
  • Pass full lowercase .sns names to high-level read and write APIs expecting domain name inputs.
  • Keep address-derivation inputs TLD-less and raw registry inputs unchanged.
  • Update record reads to consume RecordResult and its verification fields.
  • Update frontend formatting to display TLD-less SNS names with .sns.
  • If your app displays tokenized-domain artwork, download and bundle this image instead of using the NFT metadata image.