DEV Community

Cover image for Migrating from Manual Borsh to LUMOS: A Step-by-Step Guide
RECTOR SOL for LUMOS

Posted on • Originally published at docs.lumos-lang.org

Migrating from Manual Borsh to LUMOS: A Step-by-Step Guide

Tired of maintaining duplicate type definitions in Rust and TypeScript? Here's how to migrate your existing Borsh code to LUMOS.

Why Migrate?

  • Zero runtime overhead - Generated code is identical to manual Borsh
  • Type synchronization - TypeScript and Rust always match
  • Reduced maintenance - Single source of truth
  • Fewer bugs - Eliminates serialization mismatches

Migration time: 5-30 minutes per struct/enum


Step 1: Audit Your Existing Code

Find All Borsh Types

Rust:

# Find structs with Borsh derives
rg '#\[derive.*Borsh' --type rust

# Find Account macros
rg '#\[account\]' --type rust
Enter fullscreen mode Exit fullscreen mode

TypeScript:

# Find Borsh schemas
rg 'borsh\.(struct|rustEnum)' --type ts
Enter fullscreen mode Exit fullscreen mode

Step 2: Before & After Example

Before (Manual Borsh)

Rust (state.rs):

use anchor_lang::prelude::*;

#[account]
pub struct PlayerAccount {
    pub wallet: Pubkey,
    pub level: u16,
    pub experience: u64,
    pub items: Vec<Pubkey>,
}
Enter fullscreen mode Exit fullscreen mode

TypeScript (types.ts):

import { PublicKey } from '@solana/web3.js';
import * as borsh from '@coral-xyz/borsh';

export interface PlayerAccount {
  wallet: PublicKey;
  level: number;
  experience: number;
  items: PublicKey[];
}

export const PlayerAccountSchema = borsh.struct([
  borsh.publicKey('wallet'),
  borsh.u16('level'),
  borsh.u64('experience'),
  borsh.vec(borsh.publicKey(), 'items'),
]);
Enter fullscreen mode Exit fullscreen mode

After (LUMOS Schema)

Create schema/player.lumos:

#[solana]
#[account]
struct PlayerAccount {
    wallet: PublicKey,
    level: u16,
    experience: u64,
    items: [PublicKey],
}
Enter fullscreen mode Exit fullscreen mode

Generate code:

lumos generate schema/player.lumos
Enter fullscreen mode Exit fullscreen mode

That's it! Both Rust and TypeScript are generated automatically.


Step 3: Update Imports

Rust:

// OLD:
use crate::state::PlayerAccount;

// NEW:
mod generated;
use generated::PlayerAccount;
Enter fullscreen mode Exit fullscreen mode

TypeScript:

// OLD:
import { PlayerAccount, PlayerAccountSchema } from './types';

// NEW:
import { PlayerAccount, PlayerAccountBorshSchema } from './generated';
Enter fullscreen mode Exit fullscreen mode

Step 4: Verify Binary Compatibility

Critical: Ensure LUMOS-generated code produces identical bytes.

#[test]
fn test_borsh_compatibility() {
    let player = PlayerAccount {
        wallet: Pubkey::new_unique(),
        level: 10,
        experience: 5000,
        items: vec![Pubkey::new_unique()],
    };

    // Serialize with manual implementation
    let manual_bytes = player.try_to_vec().unwrap();

    // Serialize with LUMOS-generated
    let generated_bytes = player.try_to_vec().unwrap();

    assert_eq!(manual_bytes, generated_bytes, "Binary output must match!");
}
Enter fullscreen mode Exit fullscreen mode

Type Mapping Reference

Manual Rust Manual TypeScript LUMOS
Pubkey PublicKey PublicKey
u16 number u16
u64 number u64
Vec<T> T[] [T]
Option<T> `T \ undefined`
String string String
bool boolean bool

Migration Checklist

  • [ ] Install LUMOS CLI: cargo install lumos-cli
  • [ ] Create .lumos schema files
  • [ ] Generate Rust and TypeScript code
  • [ ] Update imports in existing code
  • [ ] Run binary compatibility tests
  • [ ] Remove old manual type definitions
  • [ ] Update CI/CD to regenerate on schema changes

Gradual Migration Strategy

You don't have to migrate everything at once:

  1. Phase 1: New types → Use LUMOS from the start
  2. Phase 2: High-churn types → Migrate types you change often
  3. Phase 3: Stable types → Migrate remaining types

CI/CD Integration

# .github/workflows/codegen.yml
name: Generate LUMOS Code

on: [push, pull_request]

jobs:
  generate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: cargo install lumos-cli
      - run: lumos generate schema/*.lumos
      - run: git diff --exit-code || (echo "Generated files outdated!" && exit 1)
Enter fullscreen mode Exit fullscreen mode

Get Started

cargo install lumos-cli
lumos generate your-schema.lumos
Enter fullscreen mode Exit fullscreen mode

Questions about migration? Drop them below!

Top comments (0)