Deploying Node.js Applications
This comprehensive guide covers everything you need to know about deploying Node.js applications via Deploy with Git, from simple Express servers to complex Next.js applications.
Overview
Deploy with Git automatically detects Node.js applications by looking for:
package.jsonfilepackage-lock.jsonoryarn.lockorpnpm-lock.yaml.nvmrcfor version specification
Basic Node.js Deployment
Simple Express Application
docker run -d \
--name express-app \
-e GIT_REPO_URL=https://github.com/expressjs/express \
-e APP_PORT=3000 \
-p 3000:3000 \
runonflux/:latest
What Happens Automatically
- Detection: Finds
package.jsonand identifies as Node.js project - Version Selection:
- Checks
.nvmrcfile - Checks
engines.nodein package.json - Falls back to LTS version
- Checks
- Package Manager Detection:
pnpm-lock.yaml→ Uses pnpmyarn.lock→ Uses yarnpackage-lock.json→ Uses npm
- Installation: Runs appropriate install command
- Build: Checks for build script in package.json
- Start: Uses start script or main file
Framework-Specific Guides
Next.js Applications
Next.js requires building before running. Deploy with Git handles this automatically:
docker run -d \
--name nextjs-app \
-e GIT_REPO_URL=https://github.com/vercel/next.js/tree/canary/examples/blog \
-e APP_PORT=3000 \
-p 3000:3000 \
runonflux/orbit:latest
Optimization for Next.js:
docker run -d \
--name nextjs-app-optimized \
-e GIT_REPO_URL=https://github.com/your-username/nextjs-app \
-e APP_PORT=3000 \
-e NODE_VERSION=20.11.0 \
-e BUILD_COMMAND="npm run build" \
-e RUN_COMMAND="npm run start" \
-e NODE_ENV=production \
-p 3000:3000 \
runonflux/orbit:latest
Nuxt.js Applications
docker run -d \
--name nuxt-app \
-e GIT_REPO_URL=https://github.com/your-username/nuxt-app \
-e APP_PORT=3000 \
-e BUILD_COMMAND="npm run build" \
-e RUN_COMMAND="npm run start" \
-p 3000:3000 \
runonflux/orbit:latest
Express/Fastify APIs
docker run -d \
--name api-server \
-e GIT_REPO_URL=https://github.com/your-username/express-api \
-e APP_PORT=5000 \
-e NODE_ENV=production \
-e RUN_COMMAND="node server.js" \
-p 5000:5000 \
runonflux/orbit:latest
NestJS Applications
docker run -d \
--name nestjs-app \
-e GIT_REPO_URL=https://github.com/your-username/nestjs-app \
-e APP_PORT=3000 \
-e BUILD_COMMAND="npm run build" \
-e RUN_COMMAND="npm run start:prod" \
-p 3000:3000 \
runonflux/orbit:latest
React/Vue/Angular SPAs
For single-page applications that need to be built and served:
docker run -d \
--name react-app \
-e GIT_REPO_URL=https://github.com/your-username/react-app \
-e APP_PORT=3000 \
-e BUILD_COMMAND="npm run build" \
-e RUN_COMMAND="npx serve -s build -l 3000" \
-p 3000:3000 \
runonflux/orbit:latest
Package Manager Configuration
NPM (Default)
# Use npm ci for faster, reliable installs
-e INSTALL_COMMAND="npm ci"
# Production-only dependencies
-e INSTALL_COMMAND="npm ci --production"
# With legacy peer deps (for compatibility)
-e INSTALL_COMMAND="npm ci --legacy-peer-deps"
Yarn
# Yarn with frozen lockfile
-e INSTALL_COMMAND="yarn install --frozen-lockfile"
# Yarn 2+ (Berry)
-e INSTALL_COMMAND="yarn install --immutable"
# Production only
-e INSTALL_COMMAND="yarn install --production --frozen-lockfile"
PNPM
# PNPM with frozen lockfile
-e INSTALL_COMMAND="pnpm install --frozen-lockfile"
# Production only
-e INSTALL_COMMAND="pnpm install --prod --frozen-lockfile"
Node.js Version Management
Specify Node Version
# Using specific version
-e NODE_VERSION=20.11.0
# Using LTS codename
-e NODE_VERSION=lts/iron
# Using major version
-e NODE_VERSION=18
Version Detection Priority
NODE_VERSIONenvironment variable.nvmrcfile in repositoryengines.nodein package.json- Latest LTS version
Example .nvmrc
20.11.0
Example package.json engines
{
"engines": {
"node": ">=18.0.0 <21.0.0",
"npm": ">=9.0.0"
}
}
Environment Variables
Common Node.js Variables
docker run -d \
-e GIT_REPO_URL=https://github.com/your-username/node-app \
-e APP_PORT=3000 \
-e NODE_ENV=production \
-e NODE_OPTIONS="--max-old-space-size=2048" \
-e NPM_CONFIG_LOGLEVEL=warn \
-e DATABASE_URL=postgres://user:pass@host:5432/db \
-e REDIS_URL=redis://redis-host:6379 \
-e API_KEY=your_api_key_here \
-p 3000:3000 \
runonflux/orbit:latest
Using .env Files
Create a .env file:
NODE_ENV=production
DATABASE_URL=postgres://localhost/mydb
REDIS_URL=redis://localhost:6379
API_KEY=secret_key_123
JWT_SECRET=jwt_secret_456
Your application will automatically load these with packages like dotenv.
Build Optimization
Production Builds
# Next.js production build
-e BUILD_COMMAND="npm run build"
-e NODE_ENV=production
# Custom webpack build
-e BUILD_COMMAND="webpack --mode production"
# TypeScript compilation
-e BUILD_COMMAND="tsc && npm run build"
Multi-stage Builds
# Build and optimize in sequence
-e BUILD_COMMAND="npm run clean && npm run build && npm run optimize"
# With testing
-e BUILD_COMMAND="npm test && npm run build"
Build Caching
Deploy with Git preserves node_modules between builds for faster deployments:
- First deployment: Full installation
- Subsequent updates: Only changed dependencies
Memory Management
Configure Heap Size
# Set max memory to 2GB
-e NODE_OPTIONS="--max-old-space-size=2048"
# Or use dedicated variable
-e MAX_OLD_SPACE_SIZE=2048
Memory-Intensive Applications
docker run -d \
--name memory-app \
--memory="4g" \
--memory-swap="4g" \
-e GIT_REPO_URL=https://github.com/your-username/app \
-e APP_PORT=3000 \
-e MAX_OLD_SPACE_SIZE=3072 \
-p 3000:3000 \
runonflux/orbit:latest
Process Management
Clustering with PM2
If your app includes PM2:
-e RUN_COMMAND="pm2-runtime start ecosystem.config.js"
Example ecosystem.config.js:
module.exports = {
apps: [{
name: 'app',
script: './server.js',
instances: 'max',
exec_mode: 'cluster',
env: {
NODE_ENV: 'production'
}
}]
};
Native Cluster Module
-e WEB_CONCURRENCY=4 # Number of workers
-e RUN_COMMAND="node cluster.js"
Database Migrations
Run Migrations on Deploy
# Sequelize migrations
-e PRE_BUILD_COMMAND="npx sequelize-cli db:migrate"
# Prisma migrations
-e PRE_BUILD_COMMAND="npx prisma migrate deploy"
# TypeORM migrations
-e PRE_BUILD_COMMAND="npm run typeorm migration:run"
# Knex migrations
-e PRE_BUILD_COMMAND="npx knex migrate:latest"
Safe Migration Pattern
docker run -d \
--name app-with-migrations \
-e GIT_REPO_URL=https://github.com/your-username/app \
-e APP_PORT=3000 \
-e DATABASE_URL=postgres://user:pass@db:5432/myapp \
-e PRE_BUILD_COMMAND="npm run db:backup && npm run db:migrate" \
-e POST_BUILD_COMMAND="npm run db:seed" \
-p 3000:3000 \
runonflux/orbit:latest
Private NPM Packages
Using NPM Token
# Set NPM token for private packages
-e NPM_TOKEN=your_npm_token_here
# Or configure registry
-e NPM_CONFIG_REGISTRY=https://npm.company.com/
-e NPM_CONFIG_ALWAYS_AUTH=true
.npmrc Configuration
Create .npmrc in your repository:
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
@company:registry=https://npm.company.com/
always-auth=true
Debugging Deployments
Enable Debug Logging
docker run -d \
--name debug-app \
-e GIT_REPO_URL=https://github.com/your-username/app \
-e APP_PORT=3000 \
-e LOG_LEVEL=debug \
-e DEBUG=* \
-e NODE_ENV=development \
-p 3000:3000 \
runonflux/orbit:latest
Access Container for Debugging
# Execute commands in running container
docker exec -it debug-app /bin/bash
# Check Node version
docker exec debug-app node --version
# View installed packages
docker exec debug-app npm list
# Check running processes
docker exec debug-app ps aux
Common Issues and Solutions
1. Module Not Found
Problem: Error: Cannot find module 'express'
Solution:
-e INSTALL_COMMAND="npm ci" # Use ci for clean install
2. Build Failures
Problem: Build script fails
Solution:
# Skip build if not needed
-e BUILD_COMMAND="echo 'No build required'"
# Or use custom build
-e BUILD_COMMAND="npm run build:docker"
3. Port Already in Use
Problem: Error: listen EADDRINUSE: address already in use
Solution:
# Ensure APP_PORT matches your app's actual port
-e APP_PORT=3001 # If your app uses 3001
4. Memory Errors
Problem: FATAL ERROR: Reached heap limit
Solution:
-e NODE_OPTIONS="--max-old-space-size=4096"
Performance Optimization
Production Best Practices
docker run -d \
--name production-node-app \
-e GIT_REPO_URL=https://github.com/your-username/app \
-e APP_PORT=3000 \
-e NODE_ENV=production \
-e INSTALL_COMMAND="npm ci --production" \
-e BUILD_COMMAND="npm run build:prod" \
-e RUN_COMMAND="node dist/server.js" \
-e NODE_OPTIONS="--max-old-space-size=2048" \
-e WEB_CONCURRENCY=4 \
--memory="4g" \
--cpus="2" \
-p 3000:3000 \
runonflux/orbit:latest
Caching Strategies
- Dependency Caching: Node modules are preserved between deployments
- Build Artifacts: Build outputs are retained unless code changes
- Static Assets: Consider CDN for static files
Monitoring
Health Checks
# Configure health endpoint
-e HEALTH_CHECK_PATH=/api/health
-e HEALTH_CHECK_INTERVAL=30
Implement in your app:
app.get('/api/health', (req, res) => {
res.status(200).json({ status: 'healthy' });
});
Logs
# View application logs
docker logs -f container-name
# View specific log file
docker exec container-name tail -f /app/logs/app.log
# Check error logs
docker exec container-name tail -f /app/logs/error.log
Example Deployments
Complete Next.js E-commerce
docker run -d \
--name ecommerce \
-e GIT_REPO_URL=https://github.com/vercel/commerce \
-e APP_PORT=3000 \
-e NODE_VERSION=20.11.0 \
-e DATABASE_URL=postgres://user:pass@db:5432/commerce \
-e STRIPE_SECRET_KEY=sk_test_... \
-e NEXT_PUBLIC_STRIPE_KEY=pk_test_... \
-e PRE_BUILD_COMMAND="npx prisma migrate deploy" \
-e BUILD_COMMAND="npm run build" \
-e RUN_COMMAND="npm run start" \
-p 3000:3000 \
runonflux/orbit:latest
Microservice API
docker run -d \
--name user-service \
-e GIT_REPO_URL=https://github.com/company/user-service \
-e APP_PORT=4000 \
-e NODE_ENV=production \
-e SERVICE_NAME=user-service \
-e KAFKA_BROKERS=kafka1:9092,kafka2:9092 \
-e REDIS_URL=redis://redis:6379 \
-e RUN_COMMAND="node --enable-source-maps dist/main.js" \
-p 4000:4000 \
runonflux/orbit:latest
Next Steps
- Learn about Python Deployment
- Configure CI/CD with GitHub
- Explore Troubleshooting Guide
- Read API Reference