DEV Community

Cover image for Solana CRUD from Scratch: Decentralized App
Sohail Ishaque
Sohail Ishaque

Posted on

Solana CRUD from Scratch: Decentralized App

I Built a Fully On-Chain Notes App on Solana Using Anchor + Next.js

Hey devs! πŸ‘‹

I recently built a full-stack Solana dApp where users can create, update, and delete notes that live entirely on-chain. It was a great experience to combine Anchor (Rust) for the smart contract with Next.js 14 + TailwindCSS for the frontend β€” so I thought I'd share what I learned and how I approached it.


πŸ”§ What I Built

It's a classic CRUD app β€” but on Solana!

Users can:

  • πŸ“ Create a note (title + content)
  • ✏️ Update it
  • πŸ—‘οΈ Delete it

All stored on-chain in Solana accounts using Program Derived Addresses (PDAs).

Live demo coming soon... πŸ‘€


🧱 Stack

  • 🟨 Anchor (Rust framework for Solana smart contracts)
  • βš›οΈ Next.js 14 (with App Router)
  • 🎨 TailwindCSS (for styling)
  • πŸ” @solana/wallet-adapter (wallet connection)
  • πŸ“£ SweetAlert2 (beautiful loading/toast popups)

🧠 What I Learned

  • How to structure accounts in Solana using Anchor’s #[account] macro
  • Writing validators and error handling with require! and custom #[error_code]
  • Creating PDAs using seeds:
  seeds = [b"note", author.key().as_ref(), title.as_bytes()]
Enter fullscreen mode Exit fullscreen mode


`

  • Hooking up the frontend using @project-serum/anchor and React hooks
  • Handling wallet connection state, transaction sending, and UI feedback

🧾 The Smart Contract (Rust + Anchor)

Here is a simplified view of the program logic:

`

pub fn create_note(ctx: Context<CreateNote>, title: String, content: String) -> Result<()> {
    let note = &mut ctx.accounts.note;
    let clock = Clock::get()?;

    require!(title.len() <= 100, NotesError::TitleTooLong);
    require!(!content.trim().is_empty(), NotesError::ContentIsEmpty);

    note.author = ctx.accounts.author.key();
    note.title = title;
    note.content = content;
    note.created_at = clock.unix_timestamp;
    note.last_updated = clock.unix_timestamp;

    Ok(())
}
Enter fullscreen mode Exit fullscreen mode

The Note account looks like this:

#[account]
#[derive(InitSpace)]
pub struct Note {
    pub author: Pubkey,
    #[max_len(100)]
    pub title: String,
    #[max_len(1000)]
    pub content: String,
    pub created_at: i64,
    pub last_updated: i64,
}
Enter fullscreen mode Exit fullscreen mode

πŸ–₯️ Frontend Highlights

  • Connect to wallet via @solana/wallet-adapter-react
  • Interact with the program using @project-serum/anchor
  • SweetAlert2 loading indicators
  • Tailwind UI for responsive layout
const provider = new AnchorProvider(connection, wallet, {});
const program = new Program(idl, programId, provider);

await program.methods
  .createNote(title, content)
  .accounts({ author, note, systemProgram })
  .rpc();
Enter fullscreen mode Exit fullscreen mode

πŸš€ Built with ❀️ for the Solana ecosystem

Thanks for reading!

Github :

Code

Top comments (0)