Notes on Next.js 16 + next-intl + Server Actions
What I learned wiring up AlphaNode's i18n routing alongside Server Actions and Supabase in the new App Router.
A few snags I hit while putting together the AlphaNode stack. Recording them here mostly so I find them again in six months.
1. The [locale] segment owns the root layout
The Next.js docs say "every app needs a root layout." With next-intl's localePrefix: "always", the cleanest move is to delete app/layout.tsx entirely and put <html lang={locale}> inside app/[locale]/layout.tsx. The middleware guarantees every route falls under a locale segment, so there's no orphan request without a locale.
2. setRequestLocale is not optional for static rendering
Without it, getTranslations falls back to dynamic rendering, and you lose the SSG win on locale-prefixed routes. Call it at the top of every server component that uses translations:
const { locale } = await params;
setRequestLocale(locale);
const t = await getTranslations("Dashboard");
3. Server Actions and Supabase: use the service role on the server only
The anon key can read/write through RLS policies, but for a Server Action that creates a decision log entry on behalf of the user, the cleanest path is a server-only Supabase client using SUPABASE_SERVICE_ROLE_KEY. Make sure it's not prefixed with NEXT_PUBLIC_ so it never leaks to the browser bundle.
import { createClient } from "@supabase/supabase-js";
export const supabaseAdmin = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.SUPABASE_SERVICE_ROLE_KEY!,
{ auth: { persistSession: false } }
);
4. revalidatePath with a locale-prefixed route
When you submit from /en/decision-log and want the table to refresh, you have two choices:
- Call
revalidatePath("/[locale]/decision-log", "page")— re-renders the segment across locales. - Call
revalidatePath(\/${locale}/decision-log`)` — re-renders only this locale.
For MVP I picked the segment form. It costs a few extra renders but keeps the action body simple.
That's it. Real-world i18n routing isn't hard, just fiddly. Once it's wired up correctly, you stop thinking about it.