If you're a Python developer wanting to build on Solana, the ecosystem is workable but less mature than TypeScript. The two main libraries (solana-py and solders) cover most of what you need; the patterns are similar to web3.js once you know them.
This piece is a practical guide to Solana development in Python: the libraries, the patterns, the gotchas, and when Python is the right choice versus when you should switch to TypeScript or Rust.
The Python Solana Ecosystem
Two main libraries:
solana-py. The longer-standing Python Solana SDK. Provides Connection-style classes, transaction building, RPC method wrappers. Mature but slower-moving than the JS ecosystem.
solders. Newer, Rust-backed Python bindings that provide low-level types (Pubkey, Keypair, Signature) with much better performance than pure-Python equivalents. Often used alongside solana-py.
Modern Python Solana code typically uses both: solders for types, solana-py for higher-level RPC interactions.
Installation
pip install solana solders
Or with poetry / uv. Both are well-supported on PyPI.
Basic RPC Connection
The Python pattern:
from solana.rpc.api import Client
from solders.keypair import Keypair
from solders.pubkey import Pubkey
# Connect to RPC
client = Client("https://your-rpc-url.example/?api-key=...")
# Generate or load a keypair
sender = Keypair() # or Keypair.from_bytes(...)
# Query balance
balance = client.get_balance(sender.pubkey())
print(balance.value) # Lamports
Familiar shape if you've used web3.js. The library hides JSON-RPC details.
Sending Transactions
from solders.message import Message
from solders.transaction import Transaction
from solders.system_program import TransferParams, transfer
from solana.rpc.types import TxOpts
# Build a transfer
ix = transfer(TransferParams(
from_pubkey=sender.pubkey(),
to_pubkey=recipient.pubkey(),
lamports=1_000_000,
))
# Get blockhash, build transaction, sign, send
recent_blockhash = client.get_latest_blockhash().value.blockhash
# Build and sign the transaction using solders
msg = Message.new_with_blockhash([ix], sender.pubkey(), recent_blockhash)
tx = Transaction([sender], msg, recent_blockhash)
result = client.send_transaction(
tx,
opts=TxOpts(skip_preflight=True, max_retries=0),
)
print(result.value) # Signature
The patterns mirror web3.js with Python idioms.
Common Python-Specific Considerations
Async vs sync. solana-py has both sync (Client) and async (AsyncClient) variants. For high-volume code, use async. For scripts, sync is fine.
Type stubs. Decent but not perfect. Some methods don't have full type hints. Be ready for # type: ignore occasionally.
Performance. Pure Python is slower than JS for some operations. Where it matters (signing, deserialisation), solders provides Rust-backed implementations that close the gap.
Library versioning. solana-py and solders move semi-independently. Watch for compatibility issues; pin versions in production.
When Python Makes Sense for Solana
Python is the right choice when:
- You're already in a Python ecosystem. ML pipelines, data engineering, existing Python services.
- Backend trading bots in Python-heavy stacks. Some quant shops are Python-first.
- Research and analysis. Pandas + Python's analytical ecosystem are great for backtesting and data analysis.
- Rapid prototyping. Python's iteration speed beats Rust for exploration.
Python is the wrong choice when:
- Building dApp frontends. Use TypeScript (browsers don't run Python well).
- Writing Solana programs. Rust only.
- Sub-millisecond latency requirements. Use Rust.
- You don't already have Python expertise. TypeScript is more idiomatic for Solana.
Common Python Solana Patterns
Async batch RPC calls:
import asyncio
from solana.rpc.async_api import AsyncClient
async def fetch_many(client, pubkeys):
tasks = [client.get_account_info(pk) for pk in pubkeys]
return await asyncio.gather(*tasks)
async with AsyncClient("https://your-rpc.example") as client:
results = await fetch_many(client, [key1, key2, key3])
For better performance, prefer getMultipleAccountsInfo (one round-trip) where applicable.
Transaction signing with versioned transactions:
from solders.message import MessageV0
from solders.transaction import VersionedTransaction
msg = MessageV0.try_compile(
payer=signer.pubkey(),
instructions=[your_instruction],
address_lookup_table_accounts=[],
recent_blockhash=blockhash,
)
tx = VersionedTransaction(msg, [signer])
Versioned transactions support more accounts than legacy transactions; needed for many Jupiter routes.
Subscription example:
from solana.rpc.websocket_api import connect
async with connect("wss://your-rpc.example") as websocket:
await websocket.account_subscribe(pubkey)
async for msg in websocket:
# Handle account change
pass
WebSocket support exists; quality depends on your provider.
Common Python Mistakes
Using sync client for async-natural code. If you're doing many concurrent operations, async is dramatically better.
Not pinning library versions. solana-py and solders evolve; production code should pin.
Building transactions inefficiently. Naive Python signing is slow; use solders-backed types.
Forgetting to handle RPC errors. Network errors, rate limits, transaction failures. Build defensive code.
Treating it like fully-typed code. Type hints are partial. Don't trust them blindly; test.
Trading Bots in Python
Python is reasonable for some trading bot styles:
Strategy / research bots. Pandas-driven backtest, regime detection, signal generation. Python excels.
Moderate-frequency execution bots. Sub-second is achievable. Sub-100ms is harder; consider hot-path in Rust with Python orchestration.
Backend services for trading systems. API servers, monitoring, dashboards. Python is fine.
For sub-100ms or HFT, write the hot path in Rust and orchestrate from Python.
What to Do This Week
If you're starting Solana in Python:
- Install
solana-pyandsolders. Both. - Set up
AsyncClientfor any production code. Sync for quick scripts. - Use environment variables for RPC URLs. Same pattern as elsewhere.
- Build per-signature telemetry. Same value as in any language.
- For trading bots, plan the Rust escape hatch. If you need more speed later, you'll want hot path in Rust.
- Pin library versions. Pinning isn't optional in production.
Try BoltTx From Python
from solana.rpc.api import Client
from solana.rpc.types import TxOpts
client = Client("https://bolttx.io/?api-key=YOUR_API_KEY")
# ... build your transaction ...
result = client.send_transaction(
tx,
opts=TxOpts(skip_preflight=True, max_retries=0),
)
Free tier signup. Works the same from Python as from any other language.
FAQ
Is solana-py actively maintained?
Yes, though slower-moving than the JS ecosystem. Watch GitHub for updates.
What about anchorpy?
anchorpy provides Anchor-style client generation for Python. Useful if you're calling Anchor programs from Python.
Can I write Solana programs in Python? No. Programs are Rust. Python is for client code only.
Performance difference vs TypeScript?
For RPC-bound work, similar. For CPU-bound work (signing, serialisation), Python with solders is competitive; without it, slower.
Which is better, solana-py or solders?
Use both. solders for low-level types (faster); solana-py for high-level RPC interactions.