When I first started working with Next.js and the Binance API, I ran into a frustrating error that stopped my project in its tracks. The error looked like this:
Error serializing `.res` returned from `getServerSideProps` in "/dashboard".
Reason: `undefined` cannot be serialized as JSON. Please use `null` or omit this value.
At first, I wasn’t sure what this meant. But after some debugging, I realized the root cause: Next.js requires that everything returned from getServerSideProps
must be JSON serializable. That means no undefined
, no Error
objects, no functions, and no complex classes just plain objects, arrays, strings, numbers, booleans, or null
.
Let me walk you through the problem, the fix, and how I improved my code along the way.
The Broken Code
Here’s the first version of my code:
import binance from "../config/binance-config";
export async function getServerSideProps() {
const res = await binance.balance((error, balances) => {
console.info("BTC balance: ", balances.BTC.available);
});
return {
props: {
res,
},
};
}
The issue is that binance.balance
is callback-based. It doesn’t actually return anything. I was trying to await
a function that doesn’t support promises, so res
became undefined
. And when Next.js tried to serialize undefined
into JSON, it blew up with that error.
The Fix Version
To solve this, I wrapped the Binance callback in a Promise, so I could use it with await
and safely pass plain JSON to my React component.
// pages/dashboard.js
import binance from "../config/binance-config";
export async function getServerSideProps() {
try {
// Wrap callback in a Promise
const balances = await new Promise((resolve, reject) => {
binance.balance((error, data) => {
if (error) return reject(error);
resolve(data);
});
});
// Extract just the BTC balance
const btc = {
available: balances?.BTC?.available ?? null,
onOrder: balances?.BTC?.onOrder ?? null,
};
return {
props: {
btc, // serializable
},
};
} catch (err) {
return {
props: {
btc: null,
error: err.message || "Something went wrong",
},
};
}
}
export default function Dashboard({ btc, error }) {
if (error) return <p>Error: {error}</p>;
if (!btc) return <p>No BTC data found.</p>;
return (
<div>
<h1>Dashboard</h1>
<p>BTC Available: {btc.available}</p>
<p>BTC On Order: {btc.onOrder}</p>
</div>
);
}
My Binance Config
I also cleaned up my API keys by moving them into .env.local
:
// config/binance-config.js
import Binance from "node-binance-api";
const binance = new Binance().options({
APIKEY: process.env.BINANCE_API_KEY,
APISECRET: process.env.BINANCE_API_SECRET,
});
export default binance;
And in .env.local
:
BINANCE_API_KEY=your_api_key
BINANCE_API_SECRET=your_api_secret
This way, I don’t risk pushing secrets to GitHub by mistake.
Extra Practice Functionality
Once I had BTC working, I wanted to make my dashboard more useful. Instead of just showing Bitcoin, I extended it to display multiple coins in a table.
Fetching Multiple Coins
const selectedCoins = ["BTC", "ETH", "BNB"];
const filteredBalances = selectedCoins.map((coin) => ({
symbol: coin,
available: balances?.[coin]?.available ?? null,
onOrder: balances?.[coin]?.onOrder ?? null,
}));
return {
props: {
balances: filteredBalances,
},
};
Displaying the Data in a Table
export default function Dashboard({ balances }) {
if (!balances) return <p>No balances found.</p>;
return (
<div>
<h1>My Balances</h1>
<table>
<thead>
<tr>
<th>Coin</th>
<th>Available</th>
<th>On Order</th>
</tr>
</thead>
<tbody>
{balances.map((b) => (
<tr key={b.symbol}>
<td>{b.symbol}</td>
<td>{b.available}</td>
<td>{b.onOrder}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
Now I can see all my selected coin balances in a clean table whenever I load the dashboard page.
Final Thought
Running into serialization errors in Next.js can be frustrating, but the fix is usually straightforward once you remember that only plain JSON is allowed in props. By wrapping the Binance API in a Promise and carefully structuring the data I return, I not only solved the error but also built a functional crypto dashboard.
This project started as a small debugging exercise, but it became a neat little playground where I can fetch and display my balances in real time. The best part? I now feel much more confident handling server side rendering and API integration in Next.js.