DEV Community

Ajiri Osiobe
Ajiri Osiobe

Posted on

Solana Transactions Through a Backend Developer’s Eye

Coming from Web2 backend systems, I used to think blockchain interactions were just API calls: send a request, get a response, and move on.

Solana quickly broke that assumption.

When I built a simple SOL transfer script using @solana/kit, I realized a Solana transaction is not a request. It’s a fully constructed, signed, time-bound execution unit that the network will attempt to run exactly as specified.

Unlike Web2, where the server hides most complexity, Solana forces you to explicitly define almost everything.

You build the transaction message step by step, attach instructions, set the fee payer, and bind it to a recent blockhash that determines how long the transaction remains valid:

const transactionMessage = pipe(
  createTransactionMessage({ version: 0 }),
  (tx) => setTransactionMessageFeePayerSigner(signer, tx),
  (tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
  (tx) => appendTransactionMessageInstruction(
    getTransferSolInstruction({
      source: signer,
      destination,
      amount: lamportAmount,
    }),
    tx
  )
);
Enter fullscreen mode Exit fullscreen mode

What stood out immediately is that nothing is implicit. Even basic assumptions from Web2—like request validity, authentication flow, or execution context—must be expressed directly in the transaction structure.

After building the message, you still have to explicitly sign and serialize it:

const signedTransaction = await signTransactionMessageWithSigners(transactionMessage);
const wireTransaction = getBase64EncodedWireTransaction(signedTransaction);
Enter fullscreen mode Exit fullscreen mode

This separation is important. In Web2 systems, signing is often hidden behind middleware (sessions, JWTs, auth guards). In Solana, signing is a first-class step. The transaction cannot exist in the network without it.

Then comes another major mental shift: submitting a transaction is not the end of the process.

On Solana, you don’t just send a request and receive a response. You submit a transaction and then track its lifecycle across different levels of network certainty:

  • processed → included in a block
  • confirmed → voted on by a supermajority
  • finalized → irreversible

This is why I had to implement a small status tracker:

await waitForCommitment(rpc, signature, "confirmed");
await waitForCommitment(rpc, signature, "finalized");
Enter fullscreen mode Exit fullscreen mode

It feels less like an API call and more like tracking a distributed job through eventual consistency.

Even failure handling is fundamentally different. Errors are not hidden behind a server response—they exist as on-chain transaction results. You debug them through simulation, logs, and signature status queries instead of stack traces or HTTP error codes.

The biggest mental shift for me was this:

Web2: request → response
Solana: signed state transition → network execution → probabilistic finality

Once that clicked, everything else started making sense. Transactions stopped feeling like “sending data” and started feeling like constructing precise instructions for a distributed runtime that enforces correctness at execution time.

That’s the real difference—and the hardest part to unlearn coming from backend development.

Top comments (0)