Securing Secrets in Next.js: What I Fixed Before Shipping to Production

Why This Post Exists
When building a Next.js application, it’s easy to focus on features and forget that working code is not always safe code.
Before shipping my app to production, I had to revisit how secrets and API keys were handled — and fix a few risky patterns that were fine in local development but unacceptable in production.
This post explains what I fixed and the reasoning behind it.
The Initial Problem: Client-Side Secrets
In the early version of the app, some API keys were accessible on the client using NEXT_PUBLIC_* environment variables.
This is a common mistake.
Anything exposed to the browser:
- can be viewed in DevTools
- can be extracted by anyone
- should be treated as public
That’s acceptable for anonymous IDs, but never for service keys, automation tokens, or AI credentials.
The Fix: Move Sensitive Logic to the Server
The solution was straightforward:
- All sensitive operations were moved to server-side API routes
- Secrets are now accessed only via
process.envon the server - The frontend calls internal APIs instead of third-party services directly
This ensures:
- API keys never reach the browser
- Requests can be validated and logged
- Business logic remains protected
Using API Routes as Security Boundaries
Next.js API routes became a clean security boundary:
- The client sends only the required input
- The server performs validation
- External services are called securely from the backend
This also makes it easier to:
- rotate keys
- add rate limiting
- audit usage
Webhooks and Automation: Extra Care Required
For async processing and automation workflows:
- Webhook endpoints validate a shared secret
- Payloads are strictly validated
- No automation tokens or secrets are exposed to the client
Even if someone discovers the endpoint URL, they cannot trigger it without proper authentication.
What Changed After These Fixes
After moving secrets server-side:
- No sensitive keys are exposed in the browser
- The app is safe to deploy publicly
- Logs no longer risk leaking credentials
- Production deployments feel predictable and controlled
Most importantly, the system now follows the principle of least privilege.
Key Takeaways
If you’re building with Next.js:
- Treat
NEXT_PUBLIC_*variables as public - Keep secrets on the server
- Use API routes as security boundaries
- Validate every external request
Shipping fast is good — but shipping securely is better.