RTL and Persian Fonts in Next.js 15: A Complete Guide From Layout to Production
By Arash Latifi
Persian website with Next.js 15: dir and lang setup, Vazirmatn font with font-display swap, shift-free images with next/image and PPR. Full code, comparison table and deploy checklist.
TL;DR: Three lines cover ninety percent:
lang="fa" dir="rtl"on thehtmltag, a Persian font withfont-display: swapandunicode-range, and explicit width and height onnext/image. The rest of this post is the detail behind those three lines, plus a v14 vs v15 table and a deploy checklist.
Why Next.js 15 Is Better for Persian Sites
Three things got better for us RTL folks: cleaner dir="rtl" support, granular caching with use cache, and hybrid rendering with PPR that serves the page skeleton from the build and hydrates the personal parts live. The result: faster First Paint and less CLS — the same two numbers we said move Google rankings in the site speed guide.
Step 1: Declare the html Tag as Persian
That single line fixes the direction of every margin, padding, float and text-align. Most "why is my Persian layout broken" bugs come from this missing line, not from your CSS.
Step 2: A Light Persian Font With No Flash
Two golden rules: font-display: swap means text renders instantly in a system font until the Persian font arrives (no blank page). unicode-range means the browser downloads only the Arabic-Persian range — roughly 15KB instead of 100KB.
Step 3: Sized Images, Zero Layout Shift
Giving width and height lets the browser reserve the space before the image loads, so the page never jumps (CLS near zero). This is what we did on our portfolio and it took LCP from 6 seconds to under 2.
Step 4: PPR for Mixed Pages
If your page has both static parts (header, footer) and personal parts (cart, user panel), PPR pre-renders the static skeleton and injects the personal parts at visit time. Users see content sooner and the server sweats less.
Comparison Table: Next.js 14 vs 15 for Persian Sites
| Feature | Next.js 14 | Next.js 15 |
| :--- | :--- | :--- |
| rtl support | Manual with extra classes | Clean with dir |
| font-display | Manual | Ready-made pattern in docs |
| Image sizing | Manual with fill | Automatic ratio calculation |
| PPR | Experimental | Production-ready |
| Data cache | Per-request | Granular with use cache |
Checklist Before Deploying a Persian Site
- [ ] The
htmltag has bothlang="fa"anddir="rtl" - [ ] Persian font uses
font-display: swapwith a narrowunicode-range - [ ] Every image has explicit
widthandheight - [ ] Only needed font weights load (400 and 700 are enough)
- [ ] Text is readable in the fallback system font (test with fonts blocked)
- [ ] Page tested with a Persian keyboard and Persian digits
FAQ
Why do some spots stay left-aligned despite a correct dir?
That component probably has hardcoded text-left, ml- or mr-. In Tailwind use ms-, me- and text-start, which flip with the page direction.
Text briefly shows in another font on load — is that normal?
Yes, it is called FOUT and it is intentional with swap — better than a blank page. If it bothers you, cut font weights so the font arrives sooner; do not remove swap.
Where should Persian digits go?
Article text: Persian digits. Prices, code and phone numbers: Latin digits with dir="ltr" on that fragment so digit order does not break.
Wrap-Up
A good Persian site has no complex formula: correct direction, light font, sized images. Get those three right and both users and Google are happy. If you are getting a corporate website built for your business, put this checklist in the contract from day one: "delivery with LCP under 2.5 seconds on mobile".