A small Next.js 14 starter that renders a live news feed and per-category pages. The home page is server-rendered on each request; category pages use incremental static regeneration (ISR). Headlines come from the newsdata.io news API (https://newsdata.io) — grab a free API key to run it.
The data layer is a single typed client (lib/newsdata.ts) that you can reuse
outside the example pages. It targets the free /latest endpoint by default,
so a brand-new free key works with no extra configuration.
- Server-rendered feed of the latest headlines (App Router, React Server Components).
- Category pages (
/category/technology,/category/business, ...) built with ISR. - A typed
fetchNews()client with handling for a missing key, 401, 429, and empty results. - Keyword tags shown on every article (a free response field).
- Per-article sentiment badge and a page-level sentiment breakdown. These read the
sentiment/ai_*fields when present and fall back to a clearly labeled sample on the free plan. - One-click deploy to Vercel.
- Node.js 18.18+ (or 20+)
- A newsdata.io API key — the free tier is enough. Create one at https://newsdata.io.
git clone <your-fork-url> newsdata-nextjs-starter
cd newsdata-nextjs-starter
npm install
cp .env.example .env.local
# edit .env.local and set NEWSDATA_API_KEY
npm run devOpen http://localhost:3000.
| Variable | Required | Description |
|---|---|---|
NEWSDATA_API_KEY |
yes | Your newsdata.io API key. |
NEWSDATA_LANGUAGE |
no | Default language ISO code. Defaults to en. |
NEWSDATA_PAID |
no | Set to 1 to allow paid-only query params (see below). |
app/page.tsxsetsdynamic = 'force-dynamic'and fetches withcache: 'no-store', so the feed is rendered fresh on every request.app/category/[category]/page.tsxsetsrevalidate = 600and pre-builds the known categories withgenerateStaticParams, so each category page is cached and refreshed in the background every 10 minutes.lib/newsdata.tsbuilds the request, readsNEWSDATA_API_KEYfrom the environment, and maps the response to typedArticleobjects. Pagination uses thenextPagecursor returned by the API (pass it back aspage).
Fields like sentiment, ai_tag, ai_summary, and content are part of the normal
response but are only populated on paid newsdata.io plans. The client always reads them
and the UI renders them when present; on a free key the sentiment widget shows a sample
clearly labeled as such, and AI tags / summaries are simply omitted.
Paid query params (for example size above 10, or timeframe) are rejected by a free
key. They are sent only when NEWSDATA_PAID=1; if such a request is rejected, the client
retries once without them so you still get free results. Configure them in .env.local:
NEWSDATA_PAID=1
NEWSDATA_PAGE_SIZE=10
NEWSDATA_TIMEFRAME=24
Set NEWSDATA_API_KEY in the project's environment variables during import.
$ npm run dev
▲ Next.js 14.2.5
- Local: http://localhost:3000
✓ Ready in 1.4s
○ Compiling / ...
GET / 200 in 820ms
A trimmed example of one item from the /latest response that the client maps:
{
"article_id": "8e0...c3",
"title": "Example headline about the technology sector",
"link": "https://example.com/article",
"source_name": "Example News",
"pubDate": "2026-06-11 09:30:00",
"keywords": ["technology", "markets"],
"sentiment": null,
"ai_summary": null
}keywords is present on the free plan; sentiment and ai_summary are null until
you use a paid plan.
app/
layout.tsx root layout
page.tsx server-rendered home feed
category/[category]/page.tsx ISR category pages
globals.css
components/
news.tsx feed, cards, sentiment + keyword UI
lib/
newsdata.ts typed newsdata.io client
MIT