In-depth Next.js guides covering App Router, RSC, ISR, and deployment. Get code examples, optimization checklists, and prompts to accelerate development.
If you're reading this, you've probably hit the same frustrating wall I did when trying to run database seeding scripts, sync jobs, or other standalone utilities in your Next.js project. You know that moment when your script crashes with "PAYLOAD_SECRET is not set" even though you can clearly see it in your .env.local file? Yeah, I've been there too.
In this guide, you'll learn exactly why this happens and the simple trick to fix it. We'll walk through a real world Facebook sync script example and show you multiple approaches to solve this common problem.
The Challenge I Faced
I was building a Next.js application with Payload CMS, and needed to run a Facebook sync script to pull in data from the Facebook API. My script looks something like this:
Next.js automatically loads environment variables for your web application, but standalone scripts that run outside of the Next.js runtime don't get this magic treatment. When you run a script with tsx, ts-node, or even plain Node.js, it doesn't know about your .env files unless you explicitly tell it to load them.
Next.js app works fine because the framework handles this behind the scenes, but your scripts are running in a different context entirely.
Example: Facebook Sync Script
Let's walk through fixing the Facebook sync script step by step. I'll show you three different approaches to solve this problem.
Step 1: Install Required Dependencies
First, make sure you have the necessary packages:
bash
pnpm add dotenv cross-env tsx
Step 2: Method 1 - Using dotenv/config (Recommended)
This is the simplest and most reliable approach. Update your script to load environment variables at the very top:
typescript
#!/usr/bin/env tsx// This MUST be the first import - it loads your .env filesimport'dotenv/config';
import { getPayload } from'payload';
import config from'@payload-config';
import { runFacebookSync } from'@/lib/payload/seed';
asyncfunctionmain() {
console.log('🚀 Starting Facebook sync...');
// Debug: Verify env vars are loadedconsole.log('✅ Environment variables loaded:', {
hasPayloadSecret: !!process.env.PAYLOAD_SECRET,
hasDbUrl: !!process.env.DATABASE_URL,
hasFacebookKey: !!process.env.FACEBOOK_API_KEY
});
try {
const payload = awaitgetPayload({ config });
awaitrunFacebookSync(payload);
console.log('✅ Sync completed!');
} catch (error) {
console.error('❌ Sync failed:', error);
process.exit(1);
}
}
main().catch(console.error);
Environment variable loading in standalone scripts is one of those "gotcha" moments that can trip up even experienced developers. The key insight is understanding that Next.js's automatic environment loading only works within the Next.js runtime, not in standalone scripts.