Skip to main content

Connect to Solana - Node.js quickstart

Get started with MetaMask Connect Solana in a Node.js application. The SDK displays a QR code in the terminal that you scan with the MetaMask mobile app to establish a connection.

Wallet Standard is browser-only

Wallet Standard features (getWallet(), wallet.features[...]) are designed for browser environments. In Node.js, use the multichain core directly via client.core.connect() and client.core.invokeMethod() to interact with Solana.

Prerequisites

Steps

1. Install dependencies

npm install @metamask/connect-solana

2. Initialize the Solana client

Create a file (for example, index.mjs) and initialize the client. In Node.js, there is no window.location, so you must set dapp.url explicitly. The supportedNetworks map uses network names (mainnet, devnet) as keys:

index.mjs
import { createSolanaClient, getInfuraRpcUrls } from '@metamask/connect-solana'

const SOLANA_MAINNET = 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'

const solanaClient = await createSolanaClient({
dapp: {
name: 'My Node.js Solana App',
url: 'https://myapp.com',
},
api: {
supportedNetworks: getInfuraRpcUrls({
infuraApiKey: 'YOUR_INFURA_API_KEY',
networks: ['mainnet'],
}),
},
})
Asynchronous client

createSolanaClient returns a promise. Always await it before using the client. The client uses a singleton multichain core under the hood — calling it multiple times returns the same underlying session.

3. Connect to MetaMask

Use the multichain core to connect with a Solana scope. A QR code appears in the terminal — scan it with the MetaMask mobile app:

await solanaClient.core.connect([SOLANA_MAINNET], [])

const session = await solanaClient.core.getSession()
const accounts = session?.sessionScopes?.[SOLANA_MAINNET]?.accounts ?? []
const address = accounts[0]?.split(':').pop()
console.log('Connected Solana address:', address)

4. Sign a message

Use invokeMethod to call the signMessage method on the Solana scope:

const message = Buffer.from('Hello from Node.js!', 'utf8').toString('base64')

const result = await solanaClient.core.invokeMethod({
scope: SOLANA_MAINNET,
request: {
method: 'signMessage',
params: {
account: { address },
message,
},
},
})
console.log('Signature:', result)

5. Disconnect

await solanaClient.disconnect()
console.log('Disconnected')

Listen for session events

Use the wallet_sessionChanged event on the multichain core to track session state:

solanaClient.core.on('wallet_sessionChanged', (session) => {
if (session?.sessionScopes) {
const solanaAccounts = session.sessionScopes[SOLANA_MAINNET]?.accounts ?? []
console.log('Solana accounts:', solanaAccounts)
} else {
console.log('Session ended')
}
})

Solana CAIP-2 scope reference

NetworkCAIP-2 scope
Mainnetsolana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp
Devnetsolana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1
note

Devnet and testnet require MetaMask Flask. Production MetaMask only supports Solana mainnet.

Full example

index.mjs
import { createSolanaClient, getInfuraRpcUrls } from '@metamask/connect-solana'

const SOLANA_MAINNET = 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'

const solanaClient = await createSolanaClient({
dapp: {
name: 'My Node.js Solana App',
url: 'https://myapp.com',
},
api: {
supportedNetworks: getInfuraRpcUrls({
infuraApiKey: 'YOUR_INFURA_API_KEY',
networks: ['mainnet'],
}),
},
})

// Connect — scan the QR code with the MetaMask mobile app
await solanaClient.core.connect([SOLANA_MAINNET], [])

const session = await solanaClient.core.getSession()
const accounts = session?.sessionScopes?.[SOLANA_MAINNET]?.accounts ?? []
const address = accounts[0]?.split(':').pop()
console.log('Connected:', address)

// Sign a message
const message = Buffer.from('Hello from Node.js!', 'utf8').toString('base64')
const result = await solanaClient.core.invokeMethod({
scope: SOLANA_MAINNET,
request: {
method: 'signMessage',
params: {
account: { address },
message,
},
},
})
console.log('Signature:', result)

// Disconnect
await solanaClient.disconnect()
console.log('Disconnected')

Run it with:

node index.mjs

Next steps