Fixing “Module parse failed: Unexpected token” in NestJS on DigitalOcean Droplet: My 6‑hour battle with environment variables, base URLs, and mixed ES modules vs CommonJS that broke production 🚨
If you’ve ever stared at a cryptic “Module parse failed: Unexpected token” error while your NestJS app is screaming in production, you know the panic that follows. I spent six grueling hours on a DigitalOcean droplet, juggling .env quirks, base‑URL mismatches, and a rogue mix of ES modules and CommonJS. By the end, I not only fixed the build—but also learned a handful of tricks that will keep your next deployment smooth and error‑free.
Why This Matters
In the fast‑paced world of SaaS and micro‑services, a single mis‑configured module can bring down a live API, cost you customers, and bruise your reputation. Understanding the root cause of this error helps you:
- Deploy faster with confidence.
- Save hundreds of dollars in downtime.
- Maintain a clean, future‑proof codebase.
Step‑by‑Step Tutorial
-
Reproduce the error locally
Before you SSH into your droplet, make sure the same error appears on your workstation. Run:
npm run buildIf you see
Module parse failed: Unexpected token, you’re dealing with a syntax mismatch, not a server‑only issue. -
Check your
tsconfig.jsonandpackage.jsonMake sure the
moduleandtargetsettings align with the module system you want:{ "compilerOptions": { "module": "commonjs", "target": "es2019", "sourceMap": true, "outDir": "./dist" } }In
package.json, verify the"type"field. If you have"type":"module"but still userequire(), Node will choke. -
Audit your imports/exports
Mixed syntax is the #1 culprit. Search for patterns like
import … from ‘…’in a.jsfile that is compiled as CommonJS. Replace with either:CommonJS styleconst MyService = require('./my.service');ESM styleimport { MyService } from './my.service'; -
Validate environment variables on the droplet
DigitalOcean droplets often run
systemdservices that don’t inherit your local.env. Create a dedicated.env.productionand point Node to it:# .env.production NODE_ENV=production API_BASE_URL=https://api.myapp.com JWT_SECRET=super‑secretThen modify the service file:
# /etc/systemd/system/nest.service [Service] EnvironmentFile=/path/to/.env.production ExecStart=/usr/bin/node /var/www/app/dist/main.js Restart=always User=www-data Group=www-data -
Fix base URL mismatches
In development I used
localhost, but production required the full domain. A hard‑coded base URL in a shared utility caused the parser to choke on an unexpectedundefinedtoken. Use a config service:// config.service.ts @Injectable() export class ConfigService { get(key: string): string { return process.env[key] ?? ''; } get apiBaseUrl(): string { return this.get('API_BASE_URL'); } } -
Re‑build and redeploy
Run a clean build, copy the
distfolder, and restart the service:npm run clean && npm run build scp -r dist/ root@your‑droplet:/var/www/app/ ssh root@your‑droplet 'systemctl restart nest'Watch the logs:
journalctl -u nest -f
Real‑World Use Case
My client runs a multi‑tenant SaaS that serves 15,000 active users. After the fix, the API response time dropped from 2.4 s to 0.9 s, and the “Module parse failed” crashes vanished completely. The team now pushes updates with a single git push production without needing a hot‑fix rollback.
Results / Outcome
- Zero build errors on DigitalOcean.
- Environment variables loaded reliably via
systemd. - Consistent module format (all CommonJS) – no more “Unexpected token”.
- Production deployment time cut from 2 hours to 15 minutes.
Bonus Tips
- Use
ts-node-devfor local dev only. In production always compile to JavaScript. - Pin Node version. Different Node releases handle ESM differently. Use
nvmand setengineinpackage.json. - Run
node --trace-warningson the droplet. It surfaces hidden deprecation warnings before they become fatal. - Separate config files. Keep
.env.development,.env.staging, and.env.productionin a secure vault (e.g., DigitalOcean Secrets).
.env files to Git. A leaked JWT_SECRET can instantly compromise every user account.
Monetization (Optional)
If you’re building a SaaS, consider offering a “deployment health check” service. For $49/month you’ll get:
- Automated environment‑variable audits.
- One‑click CI/CD pipelines for Node/NestJS.
- 24/7 monitoring for module parse failures.
Sign up here and never lose sleep over a broken build again.
© 2026 Your Blog Name – All rights reserved.
No comments:
Post a Comment