A production-ready Next.js starter template with modern tooling and best practices built-in.
🚀 Optimized for performance (React Compiler, Next.js)
🔒 Modern authentication (WorkOS AuthKit) with protected routes
⚡ Real-time database (Convex) with type-safe React hooks
🌍 Multi-language, type-safe i18n (next-intl)
🎨 shadcn/ui component library & Tailwind CSS 4
🌓 Dark mode & accessible, responsive design
📡 Full-stack observability (Effect + OpenTelemetry + Axiom)
🛡️ Security best practices (CSP, headers, env validation)
🧑💻 Fast linting/formatting (Biome), reproducible dev env (devenv)
You can choose to use devenv to take advantage of the environment already set up in devenv.nix.
Otherwise, make sure you have:
You'll then need to setup a WorkOS account. You can start here. After the entire setup process, you should have the following credentials:
WORKOS_API_KEYWORKOS_CLIENT_ID
Optionally, you can also setup an Axiom account in their platform to provide observability to your project.
Create a new GitHub repository from this template and clone it.
Then, install dependencies:
bun installSetup a convex dev deployment by running:
bun run dev:beRead more here to understand how to navigate through the convex dev prompts.
TL;DR: Login; select 'create a new project'.
Important: when prompted: 'Create a WorkOS team and enable automatic AuthKit environment provisioning for team "<your-team>"?', answer 'no' and let it exit.
This will setup a new project in the Convex dashboard, and generate a .env.local file with the following variables:
# Deployment used by `npx convex dev`
CONVEX_DEPLOYMENT=dev:<your-deployment> # team: <your-team>, project: <your-project>
NEXT_PUBLIC_CONVEX_URL=https://<your-deployment>.convex.cloud
NEXT_PUBLIC_CONVEX_SITE_URL=https://<your-deployment>.convex.siteNow that you have a CONVEX_SITE_URL, you can setup WorkOS webhooks following this section of the docs.
You should end up with a WORKOS_WEBHOOK_SECRET variable in your Convex environment variables.
Generate a password for the WorkOS cookie at least 32 characters long.
Go in the environment variables settings of your project on the Convex dashboard.
Add the following variables:
WORKOS_API_KEYfrom the WorkOS dashboardWORKOS_CLIENT_IDfrom the WorkOS dashboardWORKOS_COOKIE_PASSWORDwith the password you generated earlier
Go in the redirects page on the WorkOS dashboard. Setup a new redirect URI with the value http://localhost:3000/callback
Add that URI in the .env.local file:
NEXT_PUBLIC_WORKOS_REDIRECT_URI=http://localhost:3000/callbackRun:
bunx convex env listto get all the environment variables for your deployment. Add them to your .env.local file.
If no token is provided, then this functionality will not be enabled.
Create two dataset on the Axiom dashboard, one for traces, one for metrics. Put the chosen names on the AXIOM_DATASET and AXIOM_METRICS_DATASET environment variables in .env.example.
Depending on which edge server these datasets are deployed, write the right domain in AXIOM_DOMAIN. You can find the list in the Axiom docs.
Copy all Axiom-related variables from .env.example to .env.local. Finally, generate a token for your account in the Axiom dashboard and put it in the AXIOM_TOKEN environment variable in .env.local.
Your .env.local file now should look exactly like the one in .env.example.
Run both the Next.js frontend and the Convex backend:
bun devThe following deployment guide uses Vercel as the deployment platform, and should cost nothing under the current Convex/WorkOS/Vercel pricing plans, at the time of writing.
If you didn't already create a WorkOS production environment for another project, create a new one from the WorkOS dashboard. You'll need to add billing information, but if you use only AuthKit under the current pricing plan, you'll be fine.
Go to the authentication -> methods page and activate whatever method you want to use. Watch out: "Enterprise SSO in AuthKit" is a paid feature.
Optionally, go to the authentication -> providers page to configure the SSO providers you want to use.
Go to the Convex dashboard and provision a new production deployment.
You should find the CONVEX_SITE_URL, useful for the next step, in the settings page of your project. It should look like https://<your-deployment>.convex.site.
Now that you have a CONVEX_SITE_URL, you can setup WorkOS webhooks for the production environment following this section of the docs.
Copy the webhook secret and add it to your Convex production environment variables as WORKOS_WEBHOOK_SECRET.
Generate a password for the WorkOS cookie at least 32 characters long.
Add the following variables to your Convex production environment variables:
WORKOS_API_KEYfrom the WorkOS dashboardWORKOS_CLIENT_IDfrom the WorkOS dashboardWORKOS_COOKIE_PASSWORDwith the password you generated earlier
Go in the redirects page on the WorkOS dashboard. Setup a new redirect URI with the value https://<your-domain>/callback
This value will be needed in the last step when creating the Vercel project, so keep it handy. If you don't have a domain yet, you can do this step after creating the Vercel project.
Go to the settings page on the Convex dashboard and create a new deploy key.
This value will be needed in the last step when creating the Vercel project, so keep it handy.
Create a new Vercel project from the Vercel dashboard. Choose the "Import" option and select the repository you cloned from this template.
The build command should already be automatically set to bunx convex deploy --cmd 'bun run build'.
Configure the environment variables for Vercel as follows:
- Copy all variable from your Convex production environment and paste them.
- Add the redirect URI in the form of
https://<your-domain>/callbackasNEXT_PUBLIC_WORKOS_REDIRECT_URI. - Add the deploy key from the previous step as
CONVEX_DEPLOY_KEY.
At the end you should have the following environment variables:
WORKOS_API_KEYWORKOS_CLIENT_IDWORKOS_COOKIE_PASSWORDWORKOS_WEBHOOK_SECRETNEXT_PUBLIC_WORKOS_REDIRECT_URICONVEX_DEPLOY_KEYAXIOM_API_TOKENAXIOM_DATASETAXIOM_METRICS_DATASET
This values should be only for production.
Click deploy and pray.
If everything went well, do one last thing: add your domain as a custom domain in the Vercel project in order to match the redirect URI you set up in WorkOS.
A WorkOS account works only with a single platform, meaning that if you want to have multiple projects linked to the same WorkOS account, with different redirect URIs, on the first login of a user, they will be redirected to the URI marked as "default" in the WorkOS dashboard.
On subsequent, already logged in sessions, the user will be redirected to the correct project.
When working on a git branch different from main, Vercel will automatically generate a preview deployment. You need to configure both Convex and Vercel to be able to automatically deploy correctly.
Copy all the environment variables from your Convex development environment.
Go to the settings -> project settings page on the Convex dashboard and paste them in the Default Environment Variables field.
Go to the settings -> project settings page on the Convex dashboard and generate a new preview deployment key. It should look like preview:<your-team>:<your-project>|eyJ2....
Add the key from the previous step to your Vercel environment variables as CONVEX_DEPLOY_KEY, only for Preview.
Copy the following environment variables from your .env.local file:
WORKOS_API_KEYWORKOS_CLIENT_IDWORKOS_WEBHOOK_SECRETWORKOS_COOKIE_PASSWORDNEXT_PUBLIC_WORKOS_REDIRECT_URIAdd them only for Preview.
Not you can work on your branch with no worries.
Configure the app metadata in src/app/[locale]/layout.tsx
Learn more: Next.js Metadata Documentation
All routes are protected by authentication by default. To add an unauthenticated route, add it to the unauthenticatedPaths array in src/proxy.ts
Learn more: WorkOS AuthKit Documentation
The usual workflow:
- Add the entities definitions in
convex/schema.ts - Create all the feature-specific backend functions in
convex/[feature].ts - Create the feature-specific frontend components in
src/features/[feature]/ - Extend the app routing, making sure to handle also the loading state and the error boundaries
First, register the locale in src/i18n/routing.ts and add its native name:
export const routing = defineRouting({
locales: ["en", "it", "es"], // Add your locale
defaultLocale: "en",
localePrefix: "always",
});
export const localeNativeName: Record<Locale, string> = {
en: "English",
it: "Italiano",
es: "Español", // Add its native name here
};Then, create the translation file in messages/[locale].json using the same structure as messages/en.json:
{
"common": {
"signIn": "Iniciar sesión",
"signUp": "Registrarse"
},
"home": {
"title": "Blueprint"
}
}Learn more: next-intl docs
Use Effect.withSpan and run through the managed runtime:
import { Effect } from "effect";
import { telemetryRuntime } from "@/lib/telemetry/runtime";
const program = Effect.tryPromise(() => fetchSomething())
.pipe(Effect.withSpan("myFeature.load"));
const result = await telemetryRuntime.runPromise(program);Learn more: Effect docs
This project embeds production-grade patterns and architectural decisions:
- Feature-based folder structure (
src/features/[feature]/): co-locates components, types, and state per feature for better maintainability and scalability - Single source of truth: configuration (routing, locales, auth) defined once and imported everywhere, eliminating drift and duplication
- shadcn/ui first: composable, accessible components that you own and customize, not a rigid library dependency
- Separation of concerns: clear frontend/backend boundaries (Next.js/Convex), avoiding tangled logic and improving testability
- Zero code duplication: shared UI components (
src/components/ui/), reusable layouts, and centralized utilities - Observable by default: Effect-based telemetry with OpenTelemetry traces and metrics exported to Axiom, graceful no-op when unconfigured
Why these choices? They reduce cognitive load, prevent common bugs, make onboarding faster, and ensure the codebase scales cleanly from prototype to production.
- Framework: Next.js 16, React 19, TypeScript
- Backend: Convex (database, auth, real-time)
- Auth: WorkOS AuthKit
- Styling: Tailwind CSS 4, shadcn/ui, next-themes
- i18n: next-intl
- Observability: Effect + OpenTelemetry + Axiom (traces, metrics, error reporting)
- Code Quality: Biome, Ultracite, Husky
- Dev Env: devenv, direnv
- Testing: Vitest (unit/integration) + Playwright (E2E)
- Database migrations tooling
- Email service integration