Set up Frontend for Solana Application

Integrate, call, and interact with your Solana on-chain program using Rust and Alchemy RPC

You can check out the project in two ways:

Step 1: Get your Solana program ID

The previous guide shows you how to deploy a program to Solana devnet. Using that guide, we got the following program id:

$Eq5z52U3gGZNHVhgR1bgba8deMgtuFkpUNzd8iBsKvwJ

You can use this in the examples below, or replace it with your own.

Step 2: Create a Next.js app

From your terminal, run:

$npx create-next-app@latest solana-hello-frontend \
> --typescript \
> --eslint \
> --app \
> --src-dir \
> --tailwind \
> --import-alias "@/*"
>
>cd solana-hello-frontend

This sets up:

  • Next.js with the App Router
  • TypeScript
  • Tailwind (optional, but nice for styling)

Step 3: Install Solana web3.js and set environment variables

Install the Solana SDK:

$npm install @solana/web3.js

Create a file called .env in the root of solana-hello-frontend folder:

$touch .env

Add your Alchemy RPC URL and program ID:

$NEXT_PUBLIC_ALCHEMY_RPC_URL="https://solana-devnet.g.alchemy.com/v2/YOUR_ALCHEMY_API_KEY"
>NEXT_PUBLIC_PROGRAM_ID="Eq5z52U3gGZNHVhgR1bgba8deMgtuFkpUNzd8iBsKvwJ"

In a real app, replace the example program ID with the one from your own deployment.

Step 4: Build a minimal client UI that pings your program

We’ll make the homepage (app/page.tsx) a client component that:

  • connects a Solana wallet (e.g. Phantom)

  • builds a transaction with an instruction calling your program

  • sends it via Alchemy RPC

  • shows the signature + status

Open src/app/page.tsx and replace its contents with:

1"use client";
2
3import { useState } from "react";
4import {
5 Connection,
6 PublicKey,
7 Transaction,
8 TransactionInstruction,
9} from "@solana/web3.js";
10
11const RPC_URL = process.env.NEXT_PUBLIC_ALCHEMY_RPC_URL as string;
12const PROGRAM_ID = process.env.NEXT_PUBLIC_PROGRAM_ID as string;
13
14declare global {
15 interface Window {
16 solana?: any; // Phantom or compatible wallet
17 }
18}
19
20export default function Home() {
21 const [walletAddress, setWalletAddress] = useState<string | null>(null);
22 const [txSignature, setTxSignature] = useState<string | null>(null);
23 const [status, setStatus] = useState<string | null>(null);
24 const [loading, setLoading] = useState(false);
25
26 const connectWallet = async () => {
27 try {
28 if (!window.solana) {
29 alert("No Solana wallet found. Please install Phantom or a compatible wallet.");
30 return;
31 }
32
33 const resp = await window.solana.connect();
34 setWalletAddress(resp.publicKey.toString());
35 setStatus("Wallet connected.");
36 } catch (err) {
37 console.error(err);
38 setStatus("Failed to connect wallet.");
39 }
40 };
41
42 const pingProgram = async () => {
43 if (!walletAddress) {
44 setStatus("Connect your wallet first.");
45 return;
46 }
47
48 if (!RPC_URL || !PROGRAM_ID) {
49 setStatus("Missing RPC URL or PROGRAM_ID env vars.");
50 return;
51 }
52
53 try {
54 setLoading(true);
55 setStatus("Sending transaction...");
56 setTxSignature(null);
57
58 const connection = new Connection(RPC_URL, "confirmed");
59 const provider = window.solana;
60
61 const programId = new PublicKey(PROGRAM_ID);
62 const userPublicKey = new PublicKey(walletAddress);
63
64 // Build an instruction that calls your Hello World program
65 const instruction = new TransactionInstruction({
66 programId,
67 keys: [
68 {
69 pubkey: userPublicKey,
70 isSigner: true,
71 isWritable: false,
72 },
73 ],
74 // Your Hello World program ignores instruction data, so this can be empty
75 data: Buffer.from([]),
76 });
77
78 const transaction = new Transaction().add(instruction);
79
80 // Set fee payer and recent blockhash
81 transaction.feePayer = userPublicKey;
82 const latestBlockhash = await connection.getLatestBlockhash();
83 transaction.recentBlockhash = latestBlockhash.blockhash;
84
85 // Ask the wallet to sign the transaction
86 const signedTx = await provider.signTransaction(transaction);
87
88 // Send to the network through Alchemy RPC
89 const signature = await connection.sendRawTransaction(signedTx.serialize());
90 setTxSignature(signature);
91 setStatus("Transaction sent. Waiting for confirmation...");
92
93 // Wait for confirmation
94 await connection.confirmTransaction(
95 {
96 signature,
97 blockhash: latestBlockhash.blockhash,
98 lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
99 },
100 "confirmed"
101 );
102
103 setStatus("βœ… Success! Your program was invoked.");
104 } catch (err) {
105 console.error(err);
106 setStatus("❌ Error sending transaction. Check the browser console for details.");
107 } finally {
108 setLoading(false);
109 }
110 };
111
112 return (
113 <main className="min-h-screen flex items-center justify-center bg-slate-950 text-slate-100">
114 <div className="w-full max-w-md rounded-2xl border border-slate-800 bg-slate-900/70 p-6 shadow-xl">
115 <h1 className="mb-2 text-xl font-semibold">
116 Solana Hello World πŸ‘‹
117 </h1>
118 <p className="mb-4 text-sm text-slate-400">
119 Connect your wallet and ping your on-chain Hello World program on{" "}
120 <span className="font-semibold text-slate-100">devnet</span> using Alchemy RPC.
121 </p>
122
123 {!walletAddress ? (
124 <button
125 onClick={connectWallet}
126 className="mb-3 w-full rounded-xl bg-indigo-500 px-4 py-2 text-sm font-semibold text-white hover:bg-indigo-600 transition"
127 >
128 Connect Wallet
129 </button>
130 ) : (
131 <>
132 <div className="mb-3 text-xs text-slate-400 break-all">
133 Connected:{" "}
134 <span className="text-slate-100">{walletAddress}</span>
135 </div>
136 <button
137 onClick={pingProgram}
138 disabled={loading}
139 className={`mb-3 w-full rounded-xl px-4 py-2 text-sm font-semibold text-white transition ${
140 loading
141 ? "bg-slate-600 cursor-default"
142 : "bg-emerald-500 hover:bg-emerald-600"
143 }`}
144 >
145 {loading ? "Sending..." : "Ping Program"}
146 </button>
147 </>
148 )}
149
150 {status && (
151 <p className="mb-2 text-sm text-slate-200">
152 {status}
153 </p>
154 )}
155
156 {txSignature && (
157 <p className="text-xs text-slate-400 break-all">
158 Tx Signature:{" "}
159 <a
160 href={`https://explorer.solana.com/tx/${txSignature}?cluster=devnet`}
161 target="_blank"
162 rel="noreferrer"
163 className="text-sky-400 underline underline-offset-2"
164 >
165 View on Solana Explorer
166 </a>
167 </p>
168 )}
169 </div>
170 </main>
171 );
172}

Step 5: Run the Next.js app

$npm run dev

πŸŽ‰ Success

You now have a working Solana program deployed on Solana devnet!

Check out the next guide on how to:

  1. set up a frontend for this program
  2. invoke it using Alchemy πŸš€