A Node.js/Express API application with Neon Database integration, designed to work seamlessly in both development and production environments.
- Development: Uses Neon Local proxy with ephemeral database branches for isolated development
- Production: Connects directly to Neon Cloud Database for production workloads
- Framework: Node.js with Express, Drizzle ORM, and Neon Serverless Driver
- Database: PostgreSQL via Neon (Local for dev, Cloud for prod)
- Docker and Docker Compose
- Node.js 20+ (for local development without Docker)
- Neon account and project (Get started here)
- Sign up at Neon.tech
- Create a new project
- Get your API credentials:
NEON_API_KEY: From your Neon account settingsNEON_PROJECT_ID: From your project dashboardPARENT_BRANCH_ID: Usuallymainor your primary branch IDDATABASE_URL: Your production connection string
Copy and update the environment files:
# Copy development environment template
cp .env.development .env.dev.local
# Copy production environment template
cp .env.production .env.prod.localUpdate .env.dev.local with your Neon credentials:
NEON_API_KEY=your_actual_neon_api_key
NEON_PROJECT_ID=your_actual_project_id
PARENT_BRANCH_ID=your_parent_branch_id
ARCJET_KEY=your_arcjet_keyUpdate .env.prod.local with your production values:
DATABASE_URL=postgresql://username:password@ep-xxxxx.us-east-1.aws.neon.tech/dbname?sslmode=require
ARCJET_KEY=your_production_arcjet_keyRun the application with Neon Local for isolated development:
# Load environment variables and start development stack
export $(grep -v '^#' .env.dev.local | xargs)
docker-compose -f docker-compose.dev.yml up --buildThis will:
- β Start Neon Local proxy (creates ephemeral database branch)
- β Build and run your application
- β Enable hot reloading for development
- β Automatically connect to the ephemeral database
Access your application:
- API: http://localhost:3000
- Health check: http://localhost:3000/health
- Database:
postgres://neon:npg@localhost:5432/neondb?sslmode=require
# Install dependencies
npm install
# Load environment variables
export $(grep -v '^#' .env.dev.local | xargs)
# Start Neon Local in Docker (database only)
docker run --name neon-local -p 5432:5432 \
-e NEON_API_KEY=$NEON_API_KEY \
-e NEON_PROJECT_ID=$NEON_PROJECT_ID \
-e PARENT_BRANCH_ID=$PARENT_BRANCH_ID \
neondatabase/neon_local:latest
# In another terminal, start the app
npm run dev# Generate Drizzle migrations
docker-compose -f docker-compose.dev.yml exec acquisitions-app npm run db:generate
# Run migrations
docker-compose -f docker-compose.dev.yml exec acquisitions-app npm run db:migrate
# Open Drizzle Studio
docker-compose -f docker-compose.dev.yml exec acquisitions-app npm run db:studio# Set production environment variables
export DATABASE_URL="postgresql://username:password@ep-xxxxx.us-east-1.aws.neon.tech/dbname?sslmode=require"
export ARCJET_KEY="your_production_arcjet_key"
# Deploy production stack
docker-compose -f docker-compose.prod.yml up --build -d-
Set environment variables in your platform:
NODE_ENV=production DATABASE_URL=postgresql://username:password@ep-xxxxx.us-east-1.aws.neon.tech/dbname?sslmode=require ARCJET_KEY=your_production_arcjet_key PORT=3000 LogLevel=info -
Deploy using platform-specific commands:
# Example for Railway railway up # Example for Heroku git push heroku main
Create Kubernetes secrets and deployments:
# k8s/secrets.yaml
apiVersion: v1
kind: Secret
metadata:
name: acquisitions-secrets
type: Opaque
stringData:
database-url: 'postgresql://username:password@ep-xxxxx.us-east-1.aws.neon.tech/dbname?sslmode=require'
arcjet-key: 'your_production_arcjet_key'# Deploy to Kubernetes
kubectl apply -f k8s/- Start: Creates a fresh ephemeral branch from your parent branch
- Development: All changes are isolated to your ephemeral branch
- Stop: Automatically deletes the ephemeral branch (no cleanup needed!)
- Migrations: Run
npm run db:migratein production - Backup: Managed automatically by Neon
- Scaling: Handled by Neon's serverless architecture
-
Start Development Environment
export $(grep -v '^#' .env.dev.local | xargs) docker-compose -f docker-compose.dev.yml up --build
-
Make Your Changes
- Edit code (hot reload enabled)
- Update database schema in
src/models/ - Generate migrations:
npm run db:generate
-
Test Your Changes
# Check health curl http://localhost:3000/health # Test your API endpoints curl http://localhost:3000/api
-
Clean Up
docker-compose -f docker-compose.dev.yml down
The ephemeral database branch is automatically deleted!
Database Connection Failed
# Check if Neon Local is running
docker-compose -f docker-compose.dev.yml ps
# Check logs
docker-compose -f docker-compose.dev.yml logs neon-localEnvironment Variables Not Loading
# Verify environment variables are set
export $(grep -v '^#' .env.dev.local | xargs)
env | grep NEONPort Already in Use
# Check what's using the port
lsof -i :3000
lsof -i :5432
# Stop conflicting services
docker-compose -f docker-compose.dev.yml down# View application logs
docker-compose -f docker-compose.dev.yml logs -f acquisitions-app
# View database proxy logs
docker-compose -f docker-compose.dev.yml logs -f neon-local
# Enter application container for debugging
docker-compose -f docker-compose.dev.yml exec acquisitions-app sh- Never commit real credentials to version control
- Use environment variables for all sensitive data
- The
.env.developmentand.env.productionfiles contain templates only - Create
.env.*.localfiles for actual credentials (these are gitignored)
- Fork the repository
- Create a feature branch:
git checkout -b feature-name - Start development environment:
docker-compose -f docker-compose.dev.yml up - Make your changes and test
- Commit changes:
git commit -am 'Add feature' - Push to the branch:
git push origin feature-name - Submit a pull request
Made with β€οΈ using Neon Database