How to serve ads.txt correctly in Next.js (the fastest AdSense-compliant setup and common pitfalls)

You added ads.txt, but AdSense still shows warnings like "Not found" or "Unauthorized."
The file appears in your browser, yet the warning does not disappear in the dashboard.
Next.js is powerful, but ads.txt issues happen easily if one requirement is missed:
the file must be served correctly from the domain root.
In this article, you will learn a reliable ads.txt setup for Next.js (Pages Router and App Router), plus a clear verification flow based on Google and IAB expectations.
What is ads.txt?
ads.txt (Authorized Digital Sellers) is a file that lists authorized sellers of your ad inventory.
Its purpose is to prevent ad fraud and improve transparency.
AdSense does not always require it, but configuration problems can trigger warnings.
Also, reflected status changes can take a few days.
The most important rule is this:
ads.txt must be accessible at https://your-domain.com/ads.txt.
The correct setup in Next.js: place it in public/ads.txt
In Next.js, files in public/ are served directly from the site root.
/public/ads.txt → https://example.com/ads.txt
Procedure
- Check the
publicfolder directly under the project. - Create
public/ads.txt. - Paste the exact content shown in the AdSense dashboard.
- Save it as UTF-8 (without BOM).
- Deploy.
This is the safest and lowest-risk approach.
Serving via Route Handler (only if necessary)
You can also serve ads.txt through app/ads.txt/route.ts.
However, this adds extra risk:
- Cache behavior becomes more complex
- It is easier to break with middleware side effects
Content-Typecan accidentally stop beingtext/plain
Unless you have a strong reason, use public/ads.txt.
Common Pitfalls
1. Middleware catches /ads.txt
When middleware is enabled, /ads.txt may go through it too.
Possible results:
- Redirect to login screen
- Locale rewrite
- Forced
www/non-wwwconversion
Countermeasures
Exclude /ads.txt in your middleware matcher.
2. Multi-step redirects
If redirects chain (for example www -> non-www -> HTTPS), fetching can become unstable.
Check with curl
curl -I https://your-domain.com/ads.txt
What to verify:
- Final status is
200 - Redirects are minimal
3. Content-Type is not text/plain
Sometimes HTML is returned instead of plain text.
Check:
curl -I https://your-domain.com/ads.txt
Make sure the header includes Content-Type: text/plain.
4. Delayed reflection in AdSense
Google states that updates may take several days to reflect.
If your file is reachable with status 200, give it time before troubleshooting further.
Complete checklist
- Placed in
public/ads.txt - Reachable directly at
https://your-domain.com/ads.txt curl -Ireturns final status200- Redirects are minimal
Content-Typeistext/plain- Use "Check for updates" in AdSense
- Wait a few days
Notes for Vercel deployments
Vercel uses CDN caching.
Static files usually work fine, but reflection can be slower if you use:
- Aggressive cache settings
- Edge function routing
- Route Handler-based delivery
These setups can delay update visibility.
Summary
ads.txt itself is simple.
Problems usually come from interactions between:
- middleware
- redirect
- cache
- Content-Type
Once these factors overlap, unexpected failures become common.
The conclusion is straightforward:
Place it in public/ads.txt and verify status 200 with curl.
This is the most reproducible way to stay compliant.
Run curl -I now and confirm the basics first.
Simple checks prevent long debugging sessions.