Next.js App Router integration for the UniRate API — free currency exchange rates, conversion, historical data, and VAT rates.
Zero runtime dependencies. Works with Next.js 14+ App Router and React 18/19.
- Async RSC components —
<Price />and<ExchangeRate />render exchange data server-side with zero client JS - Server helpers —
getRate(),convert(),listCurrencies()with Reactcache()deduplication - Currency middleware — auto-detect visitor currency from geo/locale and set it via header + cookie
- Route handler — proxy UniRate API calls through your app to keep the API key server-side
- Next.js Data Cache — pass
revalidateto control ISR caching out of the box
npm install @unirate/nextSet your API key (get one free at unirateapi.com):
# .env.local
UNIRATE_API_KEY=your_api_key_here// app/page.tsx
import { Price, ExchangeRate, getRate, convert } from '@unirate/next';
export default async function Page() {
// Use components — they fetch at render time, zero client JS
return (
<div>
<p>Price: <Price amount={99.99} from="USD" to="EUR" /></p>
<p>Rate: <ExchangeRate from="USD" to="EUR" /></p>
</div>
);
}import { getRate, convert, listCurrencies, createUniRate } from '@unirate/next';
// Top-level functions use UNIRATE_API_KEY from env
const rate = await getRate('USD', 'EUR'); // 0.92
const result = await convert('USD', 'EUR', 100); // 92.50
const currencies = await listCurrencies(); // ['USD', 'EUR', ...]
// Or create a configured instance with custom options
const unirate = createUniRate({
apiKey: 'custom-key', // override env var
revalidate: 3600, // ISR: revalidate every hour
});
const rate2 = await unirate.getRate('GBP', 'JPY');Auto-detect visitor currency from Vercel/Cloudflare geo headers or Accept-Language:
// middleware.ts
import { createCurrencyMiddleware } from '@unirate/next/middleware';
export const middleware = createCurrencyMiddleware({
defaultCurrency: 'USD',
});
export const config = {
matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
};Then read the detected currency in any Server Component:
import { headers } from 'next/headers';
export default async function Page() {
const h = await headers();
const currency = h.get('x-unirate-currency') ?? 'USD';
return <Price amount={49.99} from="USD" to={currency} />;
}Keep your API key server-side by proxying through a Route Handler:
// app/api/unirate/route.ts
import { createUniRateHandler } from '@unirate/next/route';
const handler = createUniRateHandler();
export { handler as GET };Then call from client components:
// Client-side fetch (no API key exposed)
const res = await fetch('/api/unirate?path=/api/rates&from=USD&to=EUR');
const { rate } = await res.json();Async Server Component that converts an amount and renders it formatted.
| Prop | Type | Default | Description |
|---|---|---|---|
amount |
number |
— | Amount to convert |
from |
string |
"USD" |
Source currency |
to |
string |
— | Target currency |
decimals |
number |
2 |
Fraction digits |
locale |
string |
runtime | BCP-47 locale for formatting |
Async Server Component that renders a bare exchange rate.
| Prop | Type | Default | Description |
|---|---|---|---|
from |
string |
— | Base currency |
to |
string |
— | Quote currency |
decimals |
number |
4 |
Fraction digits |
locale |
string |
runtime | BCP-47 locale for formatting |
All methods throw typed errors inheriting from UniRateError:
| Error | HTTP | Meaning |
|---|---|---|
AuthenticationError |
401 | Missing or invalid API key |
ProRequiredError |
403 | Endpoint requires Pro subscription |
InvalidCurrencyError |
404 | Currency not found |
InvalidRequestError |
400 | Bad parameters |
RateLimitError |
429 | Rate limit exceeded |
The free tier allows 1,000 requests/month. Historical and time-series endpoints require a Pro subscription. See the API docs for details.
| Package | Description |
|---|---|
@unirate/react |
React hooks + client components |
@unirate/nestjs |
NestJS module |
@unirate/astro |
Astro integration |
@unirate/eleventy |
Eleventy plugin |
trpc-unirate |
tRPC v11 router |
unirate-api |
Standalone Node.js client |
MIT