Skip to content

Hot Reloading - Live UI Updates for Anchor Program Changes

Hot Reloading keeps your testing UI synchronized with your Solana program code in real-time. When you make changes and rebuild your program with anchor build, Testship automatically detects the IDL updates via WebSocket and refreshes the interface - no manual restarts, no page refreshes, no setup required.

Testship uses a sophisticated setup for instant updates:

Server Side (Node.js)

  • chokidar watches your IDL file (target/idl/*.json)
  • Ignores initial file state (no false triggers on startup)
  • Detects actual file changes in real-time
  • WebSocket Server broadcasts IDL_UPDATED message to all connected clients

Client Side (React)

  • WebSocket client connects on page load
  • Listens for IDL_UPDATED messages
  • Automatically refetches IDL from server
  • Updates React state triggering UI re-render

When you run anchor build, here’s what happens:

  1. ✅ IDL file changes (e.g., target/idl/my_program.json)
  2. ✅ Chokidar detects the change instantly
  3. ✅ Server sends WebSocket message: "IDL_UPDATED"
  4. ✅ Client receives message
  5. ✅ Client re-fetches IDL via HTTP
  6. ✅ React state updates
  7. ✅ UI re-renders with new instructions/accounts
  8. Total time: ~500ms

The hot reload process is buttery smooth:

  • No page refresh - Pure React state update
  • Form data preserved - localStorage keeps your inputs
  • Account history intact - Saved accounts remain available
  • Transaction history maintained - Past transactions still visible
  • WebSocket reconnection - Auto-reconnects if connection drops
  • Debounced reloads - Waits 500ms to batch multiple changes
  1. Make code changes to your program
  2. Run anchor build (30-60s)
  3. Stop your test script
  4. Restart test environment
  5. Reconfigure test accounts
  6. Re-enter test parameters
  7. Execute test
  8. Repeat…
  9. ⏱️ 3-5 minutes per iteration
  1. Make code changes to your program
  2. Run anchor build (30-60s)
  3. UI updates automatically
  4. Continue testing immediately
  5. ⏱️ ~1 minute per iteration

Let’s say you’re adding a new instruction:

// Add this to your program
pub fn new_feature(ctx: Context<NewFeature>, amount: u64) -> Result<()> {
// implementation
Ok(())
}

With Testship:

  1. Add code
  2. anchor build
  3. Wait ~30-60s for build
  4. Boom! New instruction appears in UI automatically
  5. Fill form, test immediately
  6. Total time: ~1 minute

Without Testship (traditional):

  1. Add code
  2. anchor build
  3. Stop test script
  4. Modify test file
  5. Add accounts
  6. Add test parameters
  7. Run test
  8. Total time: 3-5 minutes

That’s a 3-5x speed improvement per iteration! 🚀

Testship smartly handles different types of changes:

✅ New Instructions

  • Appear in search dropdown automatically
  • Form generated instantly when selected
  • Ready to test immediately
  • No page refresh needed

✅ Modified Instructions

  • Updated parameter fields appear
  • Changed account requirements reflected
  • Previous form data preserved if compatible
  • Automatic type conversion where possible

✅ Removed Instructions

  • Disappear from search
  • If currently selected, shows “instruction not found”
  • No crashes or errors

✅ Type Changes

  • Input validation updates automatically
  • Number ranges adjust (u8 → u64, etc.)
  • Account requirements update (signer badges, etc.)

During hot reload, Testship automatically preserves:

  • Connected wallet - No need to reconnect
  • Selected cluster - Stays on devnet/mainnet/local
  • Form data - Your inputs remain (via localStorage)
  • Account suggestions - Saved addresses persist
  • Transaction history - Past transactions remain visible
  • UI preferences - Dark mode, panel sizes, etc.

Hot reloading is silent by design:

  • Updates happen seamlessly in the background
  • No intrusive popups or toasts
  • Console log shows “IDL updated, refreshing…” for debugging
  • You’ll notice changes when you interact with the UI

Server (Node.js + ws)

const wss = new WebSocketServer({ server: httpServer });
const clients = new Set();
wss.on("connection", (ws) => {
clients.add(ws);
ws.on("close", () => clients.delete(ws));
});
// On IDL change
watcher.on("change", () => {
clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send("IDL_UPDATED");
}
});
});

Client (React + Custom Hook)

useWebSocket({
url: "ws://localhost:3000",
onMessage: (message) => {
if (message === "IDL_UPDATED") {
debouncedRefresh(); // Fetches new IDL after 500ms
}
},
onClose: () => {
// Auto-reconnects with exponential backoff
},
});

To avoid excessive reloads during rapid changes:

  • 500ms debounce timer - Multiple changes batched
  • Only IDL changes trigger reload - Not every file save
  • Ignores initial file state - No false reload on startup
  • Waits for build completion - No partial IDL reads

If WebSocket connection drops:

  • Exponential backoff - Waits longer between retries
  • Max 5 attempts - Avoids infinite reconnect loops
  • 3-second delay - Base reconnection interval
  • Console logs - Shows connection status for debugging

If IDL reload fails:

  • Silent failure - Doesn’t crash the UI
  • Console error - Logs the error for debugging
  • Manual refresh - User can press Ctrl+R
  • Retry button - “Refresh IDL” button in UI (if available)

Check WebSocket status:

  • Open browser console
  • Look for: “WebSocket connected” or “Attempting to reconnect…”
  • Connection count updates show active clients

1. Check WebSocket Connection

Open browser console → Look for:
✅ "WebSocket connected"
❌ "WebSocket error" or "Attempting to reconnect..."

2. Verify IDL File Exists

Terminal window
ls target/idl/*.json # Should show your program's IDL

3. Check Server Logs

Terminal running testship start should show:
"IDL file changed: /path/to/target/idl/program.json"

4. Manual Refresh

  • Press Ctrl+R (Cmd+R on Mac) to manually reload
  • Or restart Testship: testship start

5. Clear Browser Cache

  • Hard refresh: Ctrl+Shift+R (Cmd+Shift+R on Mac)
  • Clear localStorage: Console → localStorage.clear()
Add instruction → anchor build → Test immediately → Iterate

Perfect for experimenting with program design without the overhead of test scripts.

Find bug → Fix code → anchor build → Verify fix → Done

Fastest way to validate fixes - see results in seconds, not minutes.

Build feature → anchor build → UI appears → Test with wallet → Ship it

Smooth development flow that keeps you in the zone.

Tweak parameters → anchor build → See effects → Understand better

Best way to learn how Solana programs work - instant visual feedback.

Based on actual usage:

  • File Watch Latency: < 50ms (chokidar is fast!)
  • WebSocket Message: < 10ms
  • IDL Fetch: 50-100ms
  • React Re-render: 100-200ms
  • Total Reload Time: ~200-400ms ⚡
  • No full page reload - Only React state updates
  • Optimized WebSocket - Binary protocol, minimal overhead
  • Smart debouncing - Batches multiple changes
  • Local file watching - No network latency
  • Keep Testship running - It’s lightweight, leave it open
  • Build frequently - Small iterations catch errors early
  • Watch console - Useful for debugging connection issues
  • Use keyboard shortcuts - Ctrl+K for quick instruction search
  • Don’t manually refresh - Hot reload handles it automatically
  • Don’t restart Testship - Unless you need to change ports
  • Don’t clear localStorage unnecessarily - You’ll lose form data

Learn how to share your testing sessions in Session Sharing.