A client asks your agency for a dashboard, a headless storefront or a fast marketing site in Next.js. Your team knows WordPress and Webflow well. Nobody has shipped a production React app.
You can say no. You can learn on the client's budget. Or you can add a white-label Next.js team next Monday and sell the capability this week.
This post shows what to sell, how to price it, and one concrete architecture that lets a single codebase serve many client brands.
Why Next.js Is Worth Adding to Your Menu
Clients rarely ask for Next.js by name. They ask for speed, search visibility and an app that doesn't fall over.
Next.js is one answer to all three. Server rendering helps pages load fast and get indexed. React makes complex interfaces maintainable.
Here is what it unlocks compared with what most agencies sell today:
| Client request | Typical agency answer | With white-label Next.js |
|---|---|---|
| Fast marketing site | WordPress with caching plugins | Static or server-rendered pages, edge delivery |
| Custom customer portal | Plugin stack or no | Authenticated app with role-based access |
| Headless store | Theme edits | Shopify or WooCommerce backend, custom frontend |
| SaaS MVP | "Out of scope" | Full-stack app with API routes and a database |
| Large content site | Slow admin, plugin conflicts | Headless CMS plus incremental rebuilds |
You don't need to hire for any of it. You need a partner who already ships it.
What You Can Sell Overnight
Package capabilities as productised offers. Clients buy outcomes, not frameworks.
- Performance rebuild: move a slow site to Next.js and target green Core Web Vitals.
- Headless commerce frontend: keep Shopify or WooCommerce for operations, replace the storefront.
- Client portal: logins, invoices, documents, order tracking.
- MVP sprint: a scoped first version of a SaaS idea in a fixed window.
- Migration: move a legacy PHP or WordPress site without losing rankings.
Price each one as a fixed scope with a clear exclusions list. Add your margin on top of the partner's rate, not inside it.
The Margin Maths
Keep the model simple. Your partner charges you a blended day rate. You charge the client a project price.
Suppose a build needs 40 partner days. Your client price should cover those days, your project management, your account time and a contingency. If the final number only works at a tiny margin, the scope is too loose.
Three habits protect margin:
- Quote on scope, not on hours
- Put a written change-request process in every proposal
- Reserve 10 to 15 percent of the budget for revisions you can't predict
One Codebase, Many Brands: A White-Label Architecture
If you serve several clients with similar products, don't build each from scratch. Build one multi-tenant Next.js app and theme it per client.
The design:
- Tenant registry. A typed config maps each client domain to a brand: name, colours, logo, feature flags.
- Host-based resolution. The server reads the request host and picks the tenant.
- CSS variables for theming. One component library, brand tokens injected at the layout level.
- Isolated data. Every database row carries a
tenantId, enforced in the data layer, never trusted from the client. - Per-tenant environments. Separate secrets and payment keys for each brand.
Here is the tenant resolver and root layout. It works with the App Router and keeps every tenant's branding out of your component code.
// lib/tenants.ts
export type Tenant = {
id: string;
name: string;
domains: string[];
theme: { primary: string; accent: string; radius: string };
logo: string;
features: { portal: boolean; billing: boolean };
};
const tenants: Tenant[] = [
{
id: "acme",
name: "Acme Logistics",
domains: ["portal.acme-logistics.com", "acme.localhost:3000"],
theme: { primary: "#0f62fe", accent: "#ff7a1a", radius: "10px" },
logo: "/tenants/acme.svg",
features: { portal: true, billing: true },
},
{
id: "northwind",
name: "Northwind Care",
domains: ["app.northwindcare.co.uk", "northwind.localhost:3000"],
theme: { primary: "#0b7a5b", accent: "#f2b705", radius: "4px" },
logo: "/tenants/northwind.svg",
features: { portal: true, billing: false },
},
];
const byDomain = new Map(tenants.flatMap((t) => t.domains.map((d) => [d, t] as const)));
export function resolveTenant(host: string | null): Tenant {
const tenant = host ? byDomain.get(host.toLowerCase()) : undefined;
if (!tenant) throw new Error(`Unknown tenant host: ${host}`);
return tenant;
}
// app/layout.tsx
import type { CSSProperties, ReactNode } from "react";
import { headers } from "next/headers";
import { resolveTenant } from "@/lib/tenants";
export default async function RootLayout({ children }: { children: ReactNode }) {
const tenant = resolveTenant((await headers()).get("host"));
const style = {
"--brand-primary": tenant.theme.primary,
"--brand-accent": tenant.theme.accent,
"--brand-radius": tenant.theme.radius,
} as CSSProperties;
return (
<html lang="en" style={style} data-tenant={tenant.id}>
<body>{children}</body>
</html>
);
}
Two production notes:
- Fail closed. An unknown host throws. It never falls back to another tenant's data.
- Scope every query. Pass
tenant.idinto your data functions and filter on it in one place.
Using headers() makes these routes dynamic. For marketing pages that never change, build separate static deployments per tenant instead.
Hosting and Cloud Cost
Agencies often overspend here. A small Next.js site doesn't need a dedicated server.
| Workload | Sensible setup | Cost pattern |
|---|---|---|
| Brochure site, low traffic | Managed platform, free or entry tier | Near zero to low |
| Content site with CMS | Managed platform plus headless CMS | Predictable monthly |
| Portal with database | Managed platform plus managed Postgres | Scales with usage |
| Heavy custom workloads | Containers on a cloud provider | Needs monitoring and budgets |
Ask your partner to set billing alerts on day one. Cloud bills grow quietly, and a spike is your problem before it is the client's.
Keeping the Delivery Invisible
White-label means the client sees you at every touchpoint.
- Repos, CI and preview URLs sit under your accounts
- Commit author emails use your agency domain
- The partner joins your Slack as a named channel member, with your naming convention
- Handover docs carry your logo and no mention of the subcontractor
- Staging runs on your domain
Back this with an NDA and an IP assignment clause. Code should be yours the moment the client pays you.
Timezones and Handover
If your client is in the US or UK and the build team is in India, use asynchronous updates.
- Post a written brief and priorities before your day ends
- Get a staging link and a short Loom or written note the next morning
- Hold one live review per week for decisions that can't wait
Finish each ticket with a clear definition of done: code merged, preview deployed, tests passing, notes written.
Getting Paid Without Currency Headaches
Your client pays you. You pay the partner. Keep both legs simple.
- Bill clients through Stripe or bank transfer in their currency
- Pay the partner by monthly wire or multi-currency account in a currency you both fixed
- Tie partner payments to delivered milestones, not calendar dates
- Keep a written note of the exchange rate used at signing
What Goes Wrong, and How to Avoid It
- Overselling. Don't promise a feature you haven't scoped with the builder.
- Skipping discovery. Spend a paid week on requirements before fixed pricing.
- No maintenance plan. Sell a monthly retainer for updates, monitoring and fixes.
- Letting the partner talk to the client unsupervised. Keep one account owner on your side.
Turning a New Skill Into Revenue
The agencies that win with this don't pretend to have a React team. They sell a result, and they have the right engineers behind them.
INDOTREX acts as that engineering bench. Our team builds Next.js websites, custom software and headless storefronts under your brand, inside your repos and your communication channels. We document as we go, so you inherit clean code, not a mystery.
The common thread is lower technical debt. Typed code, tests on critical paths, preview deployments and written handovers mean the second year of a project costs less than the first.
Have a client waiting on a Next.js build? Book a free 15-minute engineering strategy call and we'll map the scope, team and timeline with you.




