SPL Governance Documentation

Build and run decentralized autonomous organizations with modular smart contracts on Solana.

⚡

High Performance

Built on Solana's 400ms block time with ultra-low transaction costs averaging $0.00025.

🔧

Modular Architecture

Plug in custom voting mechanisms, proposal types, and governance logic without core modifications.

🎨

NFT Integration

Native support for NFT-based governance with customizable voting weight calculations.

Installation

npm install @solana/spl-governance
yarn add @solana/spl-governance
pnpm add @solana/spl-governance
â„šī¸
Prerequisites: Make sure you have Node.js 16+ and a Solana wallet set up for development.

Quick Start

1

Initialize the SDK

Set up the SPL Governance SDK in your project:

import { Connection, PublicKey } from '@solana/web3.js';
import { GovernanceSDK } from '@solana/spl-governance';

// Initialize connection to Solana
const connection = new Connection('https://api.mainnet-beta.solana.com');

// Initialize the governance SDK
const governance = new GovernanceSDK({
  connection,
  wallet: yourWallet, // Your Solana wallet adapter
});

console.log('SPL Governance SDK initialized!');
2

Create a Governance Realm

Set up your first DAO governance realm:

// Create a new governance realm
const realmConfig = {
  name: "My DAO",
  communityMintPk: new PublicKey("your-community-token-mint"),
  councilMintPk: null, // Optional council token
  communityMintMaxVoteWeightSource: {
    type: 'SupplyFraction',
    value: new BN(1000000), // 100% of supply
  },
};

const realm = await governance.createRealm(realmConfig);
console.log('Realm created:', realm.publicKey.toString());
3

Create Your First Proposal

Submit a proposal for community voting:

// Create a proposal
const proposalConfig = {
  governancePk: realm.governance.publicKey,
  proposalOwnerRecord: ownerRecord.publicKey,
  name: "Treasury Allocation Proposal",
  descriptionLink: "https://your-dao.com/proposals/1",
  governingTokenMint: realm.communityMint,
};

const proposal = await governance.createProposal(proposalConfig);
console.log('Proposal created:', proposal.publicKey.toString());

Core Concepts

Realm

The top-level governance entity that represents your DAO. Contains all governance configuration and manages token-based voting rights.

Key Properties:
  • Community token mint
  • Optional council token mint
  • Governance configuration
  • Treasury accounts

Governance

Controls a specific treasury account and defines the rules for proposals and voting within that scope.

Configuration:
  • Voting thresholds
  • Time limits
  • Proposal deposits
  • Execution delays

Proposal

A specific action or change that the DAO can vote on. Can contain multiple instructions to execute if approved.

Lifecycle:
  • Draft → Voting → Succeeded/Defeated
  • Optional execution phase
  • Automatic state transitions

Token Owner Record

Represents a member's voting power within the governance. Created when tokens are deposited.

Features:
  • Voting weight calculation
  • Proposal ownership
  • Governance participation

Governance API

createRealm(config)

Creates a new governance realm with the specified configuration.

Parameters

Name Type Description
name string The name of the governance realm
communityMintPk PublicKey The mint address for community governance tokens
councilMintPk PublicKey | null Optional mint address for council tokens

Example

const realm = await governance.createRealm({
  name: "DeFi Protocol DAO",
  communityMintPk: new PublicKey("11111111111111111111111111111112"),
  councilMintPk: null,
  communityMintMaxVoteWeightSource: {
    type: 'SupplyFraction',
    value: new BN(1000000),
  },
});

Proposal API

createProposal(config)

Creates a new governance proposal for community voting.

Parameters

Name Type Description
governancePk PublicKey The governance account public key
name string The proposal name/title
descriptionLink string URL to the proposal description

Example

const proposal = await governance.createProposal({
  governancePk: governanceAccount.publicKey,
  proposalOwnerRecord: ownerRecord.publicKey,
  name: "Increase Treasury Allocation",
  descriptionLink: "https://dao.example.com/proposals/1",
  governingTokenMint: realm.communityMint,
});

Voting API

castVote(proposalPk, vote)

Cast a vote on an active governance proposal.

Parameters

Name Type Description
proposalPk PublicKey The proposal account public key
vote Vote Vote.Yes, Vote.No, or Vote.Abstain
voterTokenOwnerRecord PublicKey Voter's token owner record

Example

import { Vote } from '@solana/spl-governance';

// Cast a YES vote
await governance.castVote({
  proposalPk: proposal.publicKey,
  vote: Vote.Yes,
  voterTokenOwnerRecord: voterRecord.publicKey,
  payer: wallet.publicKey,
});

Treasury API

createTreasuryAccount(config)

Creates a treasury account controlled by governance.

Parameters

Name Type Description
governancePk PublicKey The governance account that will control the treasury
tokenMint PublicKey The token mint for the treasury account

Example

// Create SOL treasury
const solTreasury = await governance.createTreasuryAccount({
  governancePk: governanceAccount.publicKey,
  tokenMint: NATIVE_MINT, // SOL
});

// Create USDC treasury  
const usdcTreasury = await governance.createTreasuryAccount({
  governancePk: governanceAccount.publicKey,
  tokenMint: new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"),
});

Creating a DAO

Step-by-step guide to creating your first DAO using SPL Governance.

1

Prepare Your Token Mint

Create or use an existing SPL token as your governance token:

import { createMint } from '@solana/spl-token';

// Create a new token mint for governance
const governanceTokenMint = await createMint(
  connection,
  payer,
  mintAuthority.publicKey,
  freezeAuthority.publicKey,
  9 // decimals
);
2

Create the Realm

Establish your DAO's governance realm:

const realmConfig = {
  name: "My First DAO",
  communityMintPk: governanceTokenMint,
  councilMintPk: null, // Optional: add council governance
  communityMintMaxVoteWeightSource: {
    type: 'SupplyFraction',
    value: new BN(1000000), // 100% of token supply
  },
};

const realm = await governance.createRealm(realmConfig);
3

Configure Governance Rules

Set up voting thresholds and timing:

const governanceConfig = {
  voteThresholdPercentage: {
    type: 'YesVote',
    value: 60, // 60% yes votes required
  },
  minCommunityTokensToCreateProposal: new BN(1000000), // 1 token
  minInstructionHoldUpTime: 0,
  maxVotingTime: 3 * 24 * 60 * 60, // 3 days in seconds
};

Custom Plugins

Extend SPL Governance with custom voting mechanisms and proposal types.

Creating a Custom Voter Weight Plugin

import { VoterWeightPlugin } from '@solana/spl-governance';

// Custom plugin for quadratic voting
const quadraticVotingPlugin = new VoterWeightPlugin({
  programId: QUADRATIC_VOTING_PROGRAM_ID,
  config: {
    // Plugin-specific configuration
    votingPowerCurve: 'quadratic',
    maxVoteWeight: 100,
  }
});

// Register plugin with realm
await governance.setRealmConfig({
  realmPk: realm.publicKey,
  configArgs: {
    voterWeightAddin: quadraticVotingPlugin.programId,
    maxVoterWeightAddin: quadraticVotingPlugin.programId,
  }
});
â„šī¸
Plugin Development: Custom plugins are Solana programs that implement the voter weight interface. See the plugin development guide for details.

Treasury Management

Manage DAO treasuries and execute financial proposals.

Creating a Treasury Transfer Proposal

import { SystemProgram, LAMPORTS_PER_SOL } from '@solana/web3.js';

// Create instruction to transfer SOL from treasury
const transferInstruction = SystemProgram.transfer({
  fromPubkey: treasuryAccount.publicKey,
  toPubkey: recipient.publicKey,
  lamports: 5 * LAMPORTS_PER_SOL, // 5 SOL
});

// Create proposal with the transfer instruction
const proposal = await governance.createProposal({
  governancePk: governanceAccount.publicKey,
  proposalOwnerRecord: ownerRecord.publicKey,
  name: "Treasury Transfer: 5 SOL for Development",
  descriptionLink: "https://dao.example.com/proposals/treasury-1",
  governingTokenMint: realm.communityMint,
  instructions: [transferInstruction],
});

Basic DAO Setup

Complete example of setting up a basic DAO from scratch.

Complete DAO Setup

import { Connection, Keypair, PublicKey } from '@solana/web3.js';
import { GovernanceSDK } from '@solana/spl-governance';
import { createMint, mintTo, createAssociatedTokenAccount } from '@solana/spl-token';

async function setupBasicDAO() {
  // 1. Initialize connection and wallet
  const connection = new Connection('https://api.devnet.solana.com');
  const wallet = Keypair.generate();
  const governance = new GovernanceSDK({ connection, wallet });

  // 2. Create governance token
  const tokenMint = await createMint(
    connection,
    wallet,
    wallet.publicKey,
    null,
    9
  );

  // 3. Mint tokens to founder
  const founderTokenAccount = await createAssociatedTokenAccount(
    connection,
    wallet,
    tokenMint,
    wallet.publicKey
  );
  
  await mintTo(
    connection,
    wallet,
    tokenMint,
    founderTokenAccount,
    wallet.publicKey,
    1000000 * 10**9 // 1M tokens
  );

  // 4. Create governance realm
  const realm = await governance.createRealm({
    name: "Basic DAO",
    communityMintPk: tokenMint,
    councilMintPk: null,
    communityMintMaxVoteWeightSource: {
      type: 'SupplyFraction',
      value: new BN(1000000)
    }
  });

  console.log('DAO created successfully!');
  console.log('Realm:', realm.publicKey.toString());
  
  return { realm, tokenMint, governance };
}

Voting Examples

Examples of different voting scenarios and implementations.

Token-Based Voting

// Vote with governance tokens
async function voteWithTokens(proposalPk: PublicKey) {
  const vote = await governance.castVote({
    proposalPk,
    vote: Vote.Yes,
    voterTokenOwnerRecord: voterRecord.publicKey,
    payer: wallet.publicKey,
  });
  
  console.log('Vote cast:', vote.signature);
}

Delegated Voting

// Delegate voting power to another address
async function delegateVote(delegateTo: PublicKey) {
  const delegation = await governance.setGovernanceDelegate({
    governancePk: governanceAccount.publicKey,
    newGovernanceDelegate: delegateTo,
    voterTokenOwnerRecord: voterRecord.publicKey,
  });
  
  console.log('Vote delegated to:', delegateTo.toString());
}

NFT-Based Voting

Implement custom voting mechanisms using NFT collections as governance tokens.

Setting up NFT Governance

import { VoterWeightPlugin } from '@solana/spl-governance';

// Configure NFT-based voting
const nftVotingConfig = {
  collection: new PublicKey("your-nft-collection-address"),
  maxVoterWeight: 10000, // Max voting power
  digitialAssetType: 'NFT',
};

// Create voter weight plugin
const voterWeightPlugin = new VoterWeightPlugin({
  programId: NFT_VOTER_WEIGHT_PROGRAM_ID,
  config: nftVotingConfig,
});

// Use in realm creation
const realm = await governance.createRealm({
  name: "NFT DAO",
  communityMintPk: communityMint,
  voterWeightAddin: voterWeightPlugin.programId,
});
âš ī¸
Important: NFT-based voting requires the collection to be properly verified and registered with the governance program.

Integration Examples

React Component Example

import React, { useEffect, useState } from 'react';
import { useWallet } from '@solana/wallet-adapter-react';
import { GovernanceSDK } from '@solana/spl-governance';

export function ProposalList() {
  const { connection, publicKey } = useWallet();
  const [proposals, setProposals] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    async function fetchProposals() {
      if (!connection || !publicKey) return;
      
      const governance = new GovernanceSDK({ connection, wallet: publicKey });
      const realmProposals = await governance.getProposals(realmPk);
      
      setProposals(realmProposals);
      setLoading(false);
    }

    fetchProposals();
  }, [connection, publicKey]);

  if (loading) return 
Loading proposals...
; return (
{proposals.map(proposal => (

{proposal.account.name}

Status: {proposal.account.state}

))}
); }

Next.js API Route

// pages/api/proposals.ts
import { NextApiRequest, NextApiResponse } from 'next';
import { Connection } from '@solana/web3.js';
import { GovernanceSDK } from '@solana/spl-governance';

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  const connection = new Connection(process.env.SOLANA_RPC_URL!);
  const governance = new GovernanceSDK({ connection });
  
  try {
    const proposals = await governance.getProposals();
    res.status(200).json({ proposals });
  } catch (error) {
    res.status(500).json({ error: 'Failed to fetch proposals' });
  }
}

Node.js Backend Integration

const express = require('express');
const { Connection } = require('@solana/web3.js');
const { GovernanceSDK } = require('@solana/spl-governance');

const app = express();
const connection = new Connection('https://api.mainnet-beta.solana.com');

app.get('/api/dao/:realm/proposals', async (req, res) => {
  try {
    const governance = new GovernanceSDK({ connection });
    const proposals = await governance.getProposalsByRealm(req.params.realm);
    
    res.json({
      success: true,
      data: proposals,
      count: proposals.length
    });
  } catch (error) {
    res.status(500).json({
      success: false,
      error: error.message
    });
  }
});

app.listen(3000, () => {
  console.log('DAO API server running on port 3000');
});