Use case
Add auth and transactional email to Next.js
Install the AscendKit JS SDK, set your public key, and you get hosted auth (credentials, magic link, OAuth) plus transactional email from the same project. One user record covers both, so a signup can trigger a welcome email without wiring a webhook between two vendors.
How it works
- 1. Install the SDKAdd @ascendkit/nextjs and set your project public key via the X-AscendKit-Public-Key header. The CLI or MCP server can scaffold this for you.
- 2. Mount authUse the server and client auth hooks for credentials, magic link, and OAuth (Google, GitHub, LinkedIn). Users are created as usr_ records automatically.
- 3. Send emailAuthor a versioned email template in the portal, then send it from the SDK. AWS SES delivery, DKIM/SPF, and a verified domain are handled for you.
What does the full Next.js setup look like?
Three files and two environment variables. Mount the auth runtime, expose the catch-all auth route, wrap the app in the provider — and transactional email is already available from the same project, because it is the same platform rather than a second integration.
The environment variables come in pairs, one server-side and one exposed to the browser. Running the CLI writes them for you; setting them by hand works equally well. ASCENDKIT_ENV_KEY is your project public key and ASCENDKIT_API_URL points at the backend, each with a NEXT_PUBLIC_ twin for client-side use.
What you do not build is the part that usually takes the week: a webhook endpoint receiving user.created from an auth vendor, a retry queue for when it fails, an idempotency check so retries do not double-send, and a reconciliation job for the records that drift anyway.
import {
createAscendKitAuthRuntime,
createAuthRouteHandlers,
} from "@ascendkit/nextjs/server";
export const authRuntime = createAscendKitAuthRuntime();
export const { GET, POST } = createAuthRouteHandlers(authRuntime);How do you send a welcome email after signup?
Address the usr_ profile directly. There is no list to sync, no contact to create in an email vendor, and no webhook to fire — the user already exists in the system that sends the email.
Templates are authored and versioned in the dashboard rather than hardcoded in your app, so copy changes ship without a deploy. Each template has HTML and plain-text bodies and supports variable placeholders that resolve against the user record.
The comparison worth making is not feature-by-feature. With Clerk plus Resend, a welcome email requires a webhook endpoint, signature verification, a contact upsert into Resend, and a failure path for when the webhook does not arrive. Here it is a function call against a record that is already there.
| Step | AscendKit | Clerk + Resend |
|---|---|---|
| User created | usr_ profile | Clerk user |
| Get user into email system | Already there | Webhook + contact upsert |
| Verify webhook signature | Not applicable | Required |
| Handle webhook retries | Not applicable | Idempotency key needed |
| Reconcile drifted records | Not applicable | Periodic job |
| Vendors to configure | 1 | 2 |
Which auth providers can you enable?
Credentials, magic link, and OAuth through Google, GitHub, and LinkedIn. Providers are environment configuration rather than code, so enabling one changes the rendered sign-in form without a deploy.
Two constraints are worth knowing before you design the flow. Magic link and credentials are mutually exclusive — enabling magic link disables password sign-in for that environment, because they are alternative primary factors. OAuth combines with either.
The second is that OAuth works without you registering your own applications. AscendKit's OAuth proxy uses shared credentials, so you can ship Google and GitHub login before you have gone through each provider's app review. You can move to your own credentials later without changing your integration code.
Troubleshooting
Auth works locally but sessions do not persist in production
Cause: The client-side environment variables are missing from the deployment. NEXT_PUBLIC_ASCENDKIT_ENV_KEY and NEXT_PUBLIC_ASCENDKIT_API_URL must be set in the hosting provider, not only in .env.local.
Fix: Set both NEXT_PUBLIC_ variables in your deployment environment and redeploy. Local .env files are not uploaded.
Emails send in the dashboard test but not from the app
Cause: Sends from your application are server-side and require the secret key, which is deliberately never exposed to the browser.
Fix: Set ASCENDKIT_SECRET_KEY server-side and send from a route handler or server action, never from a client component.
Signup succeeds but no welcome email arrives
Cause: Most often an unverified sending domain rather than a code problem.
Fix: Verify your domain in the dashboard so DKIM and SPF are configured, then check the email delivery logs to see whether a send was attempted and what SES returned.
FAQ
Do I need Resend or another email provider alongside auth?
No. Auth and transactional email live in the same AscendKit project, so a verified sign-up can send a welcome email without a second vendor or a webhook bridge between them.
Does this work with the Next.js App Router?
Yes. The SDK ships server and client helpers for the App Router, including the catch-all route handler for the auth flow. Next.js 14 or later and React 18 or later are peer dependencies.
Can I use this with a Python or Go backend?
The server-side auth runtime requires Next.js. Other backends verify AscendKit access tokens instead — the Python SDK covers that, and any language can validate the JWT against the published JWKS endpoint.
Where do the user records live?
On AscendKit, in Better Auth's standard schema. That is what lets auth and email address the same profile without a sync layer between two vendors.
Related guides
- Add auth and email to Remix — the same setup where the server-side auth runtime is not available.
- Set this up with Claude Code — driving the same configuration through the MCP server instead of by hand.
- Add magic link login to Next.js — the passwordless variant of this setup, including why it cannot be combined with credentials.
- Send email without managing SES and DNS — the domain verification and DKIM work that decides whether your transactional email arrives.
- Build a user onboarding journey — what to do after the welcome email, using the same user record and your own product events.
- AscendKit vs Clerk — the head-to-head against the stack this page replaces.
Start with one API key
Auth, email, surveys, and journeys share one user record, so you ship this without stitching vendors together.
Start free