# 🟦 How to Build your first Base Mini App

By [deca12x](https://paragraph.com/@deca12x) · 2025-09-09

---

* * *

Why?
----

**By:** [**Deca**](https://farcaster.xyz/deca12x)

**Date: 9th September 2025**

The past two weekends I built two Base Mini Apps at the Aleph Hack (Aug 29-31, 2025) and ETHWarsaw (Sep 5-7, 2025) respectively.

Upon [Evan](https://farcaster.xyz/evslatts) and [Clemens](https://x.com/_clemens__)’ request, I made this mini report, which distills the _actual_ developer experience into a clear setup flow with caveats, tips, and dev tools.

Shoutout to 🍋[Limone](https://farcaster.xyz/limone.eth) , [Caso](https://farcaster.xyz/0xcaso) and [Bianc8](https://farcaster.xyz/bianc8) who gave me advice along the way.

**Follow these three steps in order to build and test your Mini App effectively.**

* * *

  

### 📚 **Step 1: Choose your SDKs wisely**

You’ll only need **two libraries**:

*   One for Mini App logic
    
*   One for wallet connection  
    

**Use one of these combos:**

1.  `farcaster/miniapp-sdk` **+** `coinbase/wallet-sdk` ← works best right now
    
2.  `coinbase/onchainkit` **+** `coinbase/wallet-sdk`
    

🚫 Avoid `farcaster/frame-sdk` - it’s deprecated and will cause issues.

🚫Don’t use BOTH `farcaster/miniapp-sdk` AND `coinbase/onchainkit` - pick one of the two.

  

Once you've picked, move on to Step 2: manifest setup.

Docs:

*   [https://miniapps.farcaster.xyz/docs/getting-started](https://miniapps.farcaster.xyz/docs/getting-started) OR [https://docs.base.org/onchainkit/getting-started](https://docs.base.org/onchainkit/getting-started)
    
*   [https://docs.cdp.coinbase.com/coinbase-wallet/coinbase-wallet-sdk/install](https://docs.cdp.coinbase.com/coinbase-wallet/coinbase-wallet-sdk/install)
    

* * *

  

### 🧾 **Step 2: Fill out the Farcaster Manifest**

Use the official manifest builder:  
[https://farcaster.xyz/~/developers/mini-apps/manifest?domain=yourdomain.com](https://farcaster.xyz/~/developers/mini-apps/manifest?domain=yourdomain.com)

  

**Hint 1:** You’ll need to generate and include five images at exact dimensions:

*   icon.png: **512×512 px**
    
*   splash.png: **400×400 px**
    
*   hero.png: **1200×630 px**
    
*   screenshot1.png: **1200×800 px**
    
*   screenshot2.png: **1200×800 px**
    

If using **Next.js**, place them in your /public folder.

You can use **Canva** to easily create documents of the correct size.

  

**Hint 2:** To generate your manifest, do not do it via the CLI!

`npx create-onchain --manifest`

Instead, to get your farcaster header, payload and signature, do it directly from the Farcaster app on your phone:

1.  Open settings
    
2.  Open advanced tab > enable developer mode
    
3.  On developer tools > domains, enter your domain and generate manifest
    
4.  Copy and paste the values of header, payload, and signature you have in the clipboard in the related env variables
    

  

✅ Once all fields are green in the manifest tool, you're ready to build out your Mini App’s functionality.

* * *

  

### 🧪 **Step 3: Testing and Debugging - What Works and What Doesn’t**

By default, simply opening your app at [localhost:3000](http://localhost:3000) and using browser devtools is **not sufficient** to test Farcaster-specific behavior.

Here’s why:

*   The SDK provides a context object (sdk.context) populated _only_ when the Mini App is rendered within a Farcaster client - like **Base App**, **Farcaster App**, or the **Farcaster manifest preview tool**.
    
*   You can test your **own** user context this way (e.g. `sdk.context.user`) via the preview site.
    
*   But if your logic depends on **other context**, like the author of the cast (`sdk.context.location.cast.author`), the preview tool won’t work - it doesn’t simulate the full cast environment.  
    

This means that to test all context fields fully, you **must push your app to production**, post a cast linking to it, and open it from Base App.

But:

*   **Pushing to prod takes time** - typically 1-5 minutes per change (depends on host like Vercel, your git branches setup, whether you test the build locally, etc.)
    
*   **You can’t access browser logs** from Base App - debugging becomes hard.
    

* * *

  

### 🧰 **Two Workable Debugging Solutions**

#### **Option 1: Use a tunneling service (e.g. ngrok)**

*   Lets you test locally using a public URL
    
*   Works with the Farcaster manifest preview site
    
*   Preserves full access to browser logs (e.g. console.log)
    
    **Setup**:
    
    *   Terminal 1: `npm run dev`
        
    *   Terminal 2: `npm run ngrok` (set up a script for this in your package.json file)
        
    *   Paste the generated URL (e.g. [random-id.ngrok.io](http://random-id.ngrok.io)) into the manifest preview tool (without **https://**)  
        

**Pros**:

*   Fast feedback loop
    
*   Easy access to logs
    

**Cons**:

*   Can't access full cast context (e.g. `sdk.context.location.cast.author`)
    
*   You might run into extra issues if your app’s logic changes based on domain (e.g. different auth providers per subdomain)
    
*   Tunnels may need to be reset often...
    
    *   Clear cookies, browser cache, and app state
        
    *   Restart both servers (`npm run dev` AND `npm run ngrok`)  
          
        

🔎 This setup is useful when you're building more complex flows.

* * *

  

#### **Option 2: Use an in-app DebugPanel component**

This is what I used:

1.  Create a component that logs and displays relevant data visually inside the Mini App  
    `if (debugMode) {     return <DebugPanel data={sdk.context} logs={clientLogs} />;   }`
    
2.  Serve the app at [yourdomain.com/?debug=true](http://yourdomain.com/?debug=true￼￼)
    
3.  Post a cast containing this URL
    
4.  Open the cast in Base App → DebugPanel is visible
    
5.  Copy-paste DebugPanel logs from your phone to your laptop (possibly feed them to an LLM)  
    

Real example I built with DebugPanel:  
🔗 [https://base.app/post/0x23f1a925729e1f3a2ae58b2385b8e72764925121](https://base.app/post/0x23f1a925729e1f3a2ae58b2385b8e72764925121)

**Pros**:

*   Full access to all real context fields ([sdk.context.location.cast.author](http://sdk.context.location.cast.author), etc.)
    
*   No compromise - this _is_ your final deployed Mini App
    

**Cons**:

*   Slow feedback loop (prod push every change)
    
*   You must manually transfer logs to your dev machine
    

  

If this was useful, please [Recast this guide](https://base.app/post/0x058f80302d06ab921bcbd576028d25957e9938a7)!  
✌Deca

---

*Originally published on [deca12x](https://paragraph.com/@deca12x/first-miniapp)*
