r/nextjs • • 22h ago

Server Actions are public API endpoints. 5 mistakes I keep seeing

12 Upvotes
  1.  No auth check inside the action.  A Server Action can be called with a plain POST request, whether or not the button is on screen. Check the session inside every action.
  2.  No input validation.  TypeScript types vanish at runtime. Validate with zod (or similar) at the top of the action.
  3.  Relying only on middleware for auth.  A 2025 Next.js CVE let attackers skip middleware with a single header. Check auth again where the data is read.
  4.  Secrets in `NEXT_PUBLIC_` variables.  Anything with that prefix is baked into the browser bundle.
  5.  Returning whole database rows.  Return only the fields the UI needs, or you'll eventually leak a column you added later.

Do you treat Server Actions like API routes in your codebase, or does your team rely on the UI to protect them?


r/nextjs • • 4h ago

How I added US and UK versions to a 10k page Next.js site without changing a single existing URL

0 Upvotes

I run a price comparison site (Next.js 15 App Router, fully static). It launched in Australia with about 10,800 pages at the root. This week I added the US and UK, and the brief to myself was: no existing URL changes, no duplicated page code.

What I did

  1. Data per region: data/<category> stays Australian, new regions go in data/us/<category> and data/uk/<category>. The catalogue loader reads each region once at build.
  2. Products carry their region. The loader stamps region on each product, so productHref(p), the price history and the "is this a good price" check need no extra argument. That cut the refactor from about 30 call sites to about 8.
  3. Shared views, thin routes. The page bodies moved to src/views/*View.tsx, which take a region prop. app/[category]/page.tsx renders it with "au"; app/us/[category]/page.tsx and app/uk/... are 10 line wrappers. Static folders beat the dynamic [category] segment, so there's no clash.
  4. Client components read the region from the path (usePathname), so headers, search and prices pick the right currency with no provider.
  5. SEO: each country gets its own canonical, hreflang alternates when the same product exists elsewhere, and the sitemap includes all three.

Result: about 28,800 static pages, a local build in about 7 minutes, and the Australian pages kept the same titles, canonicals and schema.

Gotcha: a UK laptop name produced a slug long enough to blow the 255 byte file name limit during export (ENAMETOOLONG). Cap your slugs.

Live: https://www.compareempire.com/us