# Build an MT5 Trading Dashboard with the Next.js Starter

> A working Next.js app on the fxapis MT5 API: connect an account, watch its positions and place a trade behind a confirm step — with the API key kept on the server.

Published 2026-10-08 by fxapis. Canonical: https://fxapis.com/blog/nextjs-mt5-trading-dashboard-starter

## In short

- fxapis-nextjs-starter is a small working Next.js app: connect an MT5 account, bring it online, watch its positions and place a market order.
- The API key never reaches the browser: the client is server-only, and Server Actions do every write.
- Orders go through a confirm-before-trade step that is checked again on the server, and every order carries a fresh idempotency key.
- It is single-tenant on purpose — swap one file for a database and add your own auth to make it multi-user.

[fxapis-nextjs-starter](https://github.com/FXapis/fxapis-nextjs-starter) is a small, working Next.js app on the fxapis MetaTrader 5 API — not a toy. **It connects a broker demo account, brings it online, shows its open positions, and places a market order only after an explicit confirmation step.** Everything that touches your API key or your broker credentials runs on the server; the browser never sees either.

It has three routes worth reading: `/connect` connects an account and brings it online, `/dashboard` shows the account's state, its open positions and the trade form, and `/` sends you to whichever of the two applies.

## Run it

```bash
git clone https://github.com/FXapis/fxapis-nextjs-starter.git
cd fxapis-nextjs-starter
npm install
cp .env.local.example .env.local   # add your fxapis API key
npm run dev
```

Open `localhost:3000`. With no account connected, it takes you to **Connect an account**: enter a broker **demo** account's login, server and trading password — not the investor password, which logs in but cannot trade ([connecting accounts](https://docs.fxapis.com/guides/connect-accounts) explains the difference). The key needs `accounts:read`, `accounts:write`, `trading:read` and `trading:execute`; create it in the [console](https://fxapis.com/dashboard/keys).

## How it is built

- **The API key never leaves the server.** `src/lib/fxapis-client.ts` builds the one client from `FXAPIS_API_KEY` and starts with `import "server-only"` — importing it into a Client Component is a build error, not a runtime surprise.
- **Server Actions do every write.** Connecting, bringing online, placing an order and closing a position are `"use server"` functions called straight from a form or a button. There are no separate API routes to keep in step with the UI.
- **One account, no database.** `src/lib/store.ts` remembers the connected account's id in a gitignored file — enough to try it with no setup, and the one file to replace when it stops being a demo.
- **Every order carries a fresh idempotency key**, so a resubmitted form can never place the order twice.
- **Response shapes are typed by hand** in `src/lib/types.ts`, naming only the fields the app reads, because the [TypeScript SDK](https://fxapis.com/blog/mt5-api-typescript-sdk) returns the API's data untyped.

## Confirm before trading

The trade form never sends an order on the first click. Submitting shows exactly what will be sent — side, volume and symbol — behind a required checkbox, and only a second, explicit **Confirm and send** places it. The Server Action checks the same confirmation again on the server, because a check that lives only in the browser is a convenience, not a safeguard: anything that calls the action directly would bypass it.

## Why every page is dynamic

`/` and `/dashboard` are marked `export const dynamic = "force-dynamic"`. A trading dashboard reads live state on every request, and Next.js would otherwise happily prerender it once at build time and serve that frozen snapshot in production. `/connect` is a plain form with nothing live to read, so it prerenders normally. While an account is connecting, a small client component polls every few seconds — fxapis has no event webhooks yet — and that is the one file to change when they arrive.

## Taking it further

- **A real database:** swap `store.ts` for your ORM and the app becomes multi-account and multi-user; every other file already takes the account id as a value.
- **Auth:** there is none on purpose. Put your session layer in front of `/dashboard`, as in any Next.js app.
- **More of the API:** pending orders, moving stops, multi-account orders and history are all in the SDK; the [examples repository](https://fxapis.com/blog/mt5-api-examples-python-node-curl) has patterns to copy.

## Where to go next

- [SDKs and examples](https://docs.fxapis.com/sdks) and the [Node.js guide](https://docs.fxapis.com/guides/nodejs) in the docs.
- [Trading](https://docs.fxapis.com/trading) for every outcome an order can have, before you add more order types.

## Questions

### Is the starter safe to point at a live account?

Use a broker demo account. An fx_test_ key is a label, not a sandbox: every fxapis key reaches a real broker. The starter also asks for confirmation before every order.

### Why are the dashboard pages dynamic?

A trading dashboard shows live state. Without force-dynamic, Next.js could prerender the page once at build time and serve that snapshot forever.

### How do I make it multi-user?

Replace src/lib/store.ts, which remembers one account id in a local file, with your database, and put your auth in front of /dashboard. The rest of the app already takes the account id as a value.
