Banyak engineer buang waktu berjam-jam hanya untuk setup lingkungan kerja, padahal belum satu baris kode bisnis pun ditulis. Lebih parah lagi, setup yang asal-asalan bakal jadi utang teknis yang nagih di kemudian hari: konflik versi Node, node_modules yang corrupt, atau environment dev yang beda jauh dari production.
Ini bukan artikel yang kasih kamu daftar tool tanpa konteks. Ini adalah konfigurasi yang saya pakai sendiri—di mesin macOS dan Linux—untuk proyek-proyek Node.js skala solo hingga tim kecil. Kalau kamu sudah punya setup sendiri, mungkin ada satu-dua bagian yang bisa dicuri.
Kita akan bahas nodejs development environment setup dari nol: manajemen versi, struktur proyek, environment variables, linting, dan opsional Docker untuk paritas dev-production.
Kenapa Manajemen Versi Node Itu Wajib, Bukan Opsional
Install Node langsung dari nodejs.org itu jebakan. Begitu kamu punya dua proyek—satu pakai Node 18, satu butuh Node 20—kamu sudah dalam masalah. Solusinya: nvm (Node Version Manager).
# Install nvm (versi 0.39.7, cek github.com/nvm-sh/nvm untuk terbaru)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
# Reload shell
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
# Install Node LTS terbaru
nvm install --lts
nvm use --lts
nvm alias default 'lts/*'
Setelah itu, buat file .nvmrc di root setiap proyek:
20.12.2
Lalu tambahkan ini ke .zshrc atau .bashrc supaya versi Node otomatis ganti saat masuk direktori:
autoload -U add-zsh-hook
load-nvmrc() {
local nvmrc_path
nvmrc_path="$(nvm_find_nvmrc)"
if [ -n "$nvmrc_path" ]; then
local nvmrc_node_version
nvmrc_node_version=$(nvm version "$(cat "${nvmrc_path}")")
if [ "$nvmrc_node_version" = "N/A" ]; then
nvm install
elif [ "$nvmrc_node_version" != "$(nvm version)" ]; then
nvm use
fi
fi
}
add-zsh-hook chpwd load-nvmrc
load-nvmrc
Alternatif untuk yang suka sesuatu yang lebih cepat: fnm (Fast Node Manager, ditulis dalam Rust). Perintahnya mirip nvm tapi startup-nya jauh lebih ngebut. Saya pribadi pakai fnm di mesin baru sejak 2023.
# Install fnm
curl -fsSL https://fnm.vercel.app/install | bash
# Pakai
fnm install 20
fnm use 20
fnm default 20
Struktur Proyek yang Tidak Akan Kamu Sesali
Struktur folder itu opini, tapi ada pola yang terbukti lebih mudah di-maintain. Ini yang saya pakai untuk Express/Fastify API:
my-api/
├── src/
│ ├── config/ # Konfigurasi app (db, env validation)
│ ├── controllers/ # Request handlers
│ ├── services/ # Business logic
│ ├── models/ # Data models / ORM schemas
│ ├── middlewares/ # Express middlewares
│ ├── routes/ # Route definitions
│ └── index.ts # Entry point
├── tests/
│ ├── unit/
│ └── integration/
├── .env.example
├── .nvmrc
├── .eslintrc.json
├── tsconfig.json
└── package.json
Titik kritis: jangan taruh logic di index.ts. File itu cuma untuk bootstrap—listen port, connect database, register routes. Sisanya masuk services/. Ini yang bikin unit testing tidak menjadi mimpi buruk.
Environment Variables: Jangan Hardcode, Jangan Asal .env
Pakai .env itu benar, tapi validasi environment variables itu yang sering dilupakan. Kalau DATABASE_URL kosong dan app kamu diam-diam jalan dengan nilai undefined, kamu baru tahu masalahnya saat production meledak.
Saya pakai zod untuk validasi env:
npm install zod
// src/config/env.ts
import { z } from 'zod';
const envSchema = z.object({
NODE_ENV: z.enum(['development', 'test', 'production']),
PORT: z.string().transform(Number).default('3000'),
DATABASE_URL: z.string().url(),
JWT_SECRET: z.string().min(32),
});
const parsed = envSchema.safeParse(process.env);
if (!parsed.success) {
console.error('❌ Invalid environment variables:');
console.error(parsed.error.flatten().fieldErrors);
process.exit(1);
}
export const env = parsed.data;
Sekarang kalau ada env yang kurang, app langsung crash dengan pesan yang jelas—bukan error samar di tengah request.
Jangan lupa .env.example di-commit ke repo (tanpa nilai sensitif), dan .env masuk .gitignore:
# .gitignore
.env
.env.local
.env.*.local
Linting dan Formatting: Sekali Setup, Selamanya Konsisten
Debat tabs vs spaces itu buang waktu. Otomasi saja.
ESLint + Prettier masih jadi standar de-facto di 2024. Setup minimal:
npm install -D eslint @eslint/js prettier eslint-config-prettier
// eslint.config.js (flat config, ESLint v9+)
import js from '@eslint/js';
import prettierConfig from 'eslint-config-prettier';
export default [
js.configs.recommended,
prettierConfig,
{
rules: {
'no-console': 'warn',
'no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
},
},
];
// .prettierrc
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5",
"printWidth": 100
}
Tambahkan pre-commit hook dengan lint-staged dan husky supaya kode jelek tidak pernah masuk repo:
npm install -D husky lint-staged
npx husky init
// package.json
"lint-staged": {
"*.{js,ts}": ["eslint --fix", "prettier --write"],
"*.{json,md}": ["prettier --write"]
}
# .husky/pre-commit
npx lint-staged
Satu kali setup, semua commit otomatis rapi. Tidak perlu review nitpick soal formatting lagi.
TypeScript: Aktifkan Strict Mode dari Hari Pertama
Kalau kamu mulai proyek baru, pakai TypeScript dari awal. Migrasi belakangan itu menyakitkan. Dan kalau pakai TypeScript, aktifkan strict: true—jangan setengah-setengah.
// tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "commonjs",
"lib": ["ES2022"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "tests"]
}
Untuk development, pakai tsx sebagai pengganti ts-node—jauh lebih cepat karena tidak butuh type-checking saat run:
npm install -D tsx
// package.json scripts
"scripts": {
"dev": "tsx watch src/index.ts",
"build": "tsc",
"start": "node dist/index.js",
"lint": "eslint src/",
"test": "node --experimental-vm-modules node_modules/.bin/jest"
}
Docker untuk Paritas Dev-Production (Opsional tapi Direkomendasikan)
Ini bagian yang sering dilewati solo developer—sampai production berperilaku beda dari dev. Kalau proyek kamu butuh database, Redis, atau service eksternal lain, Docker Compose adalah solusi paling pragmatis.
# docker-compose.yml
services:
app:
build:
context: .
target: development
volumes:
- .:/app
- /app/node_modules
ports:
- "3000:3000"
env_file:
- .env
depends_on:
postgres:
condition: service_healthy
postgres:
image: postgres:16-alpine
environment:
POSTGRES_USER: devuser
POSTGRES_PASSWORD: devpass
POSTGRES_DB: myapp_dev
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U devuser"]
interval: 5s
timeout: 5s
retries: 5
volumes:
postgres_data:
# Dockerfile
FROM node:20-alpine AS base
WORKDIR /app
COPY package*.json ./
FROM base AS development
RUN npm install
COPY . .
CMD ["npm", "run", "dev"]
FROM base AS production
RUN npm ci --only=production
COPY . .
RUN npm run build
CMD ["node", "dist/index.js"]
Dengan setup ini, docker compose up sudah langsung kasih kamu Node app + PostgreSQL dengan hot reload. Tidak perlu install Postgres di mesin lokal, tidak ada konflik port antar proyek.
Kalau kamu belum familiar dengan Docker untuk dev workflow, saya pernah bahas lebih dalam di cara setup Docker untuk development lokal.
Perbandingan Tool: Mana yang Pilih?
| Kebutuhan | Pilihan A | Pilihan B | Rekomendasi |
|---|---|---|---|
| Manajemen versi Node | nvm | fnm | fnm (lebih cepat) |
| TypeScript runner (dev) | ts-node | tsx | tsx |
| Linting | ESLint | Biome | ESLint (ekosistem lebih matang) |
| Formatting | Prettier | Biome | Prettier (atau Biome kalau mau all-in-one) |
| Testing | Jest | Vitest | Vitest (lebih cepat, ESM native) |
| Package manager | npm | pnpm | pnpm (disk space lebih efisien) |
Satu catatan soal Biome: tool ini menjanjikan—linting + formatting dalam satu binary Rust yang cepat. Tapi di pertengahan 2024, plugin ecosystem-nya masih jauh di bawah ESLint. Kalau proyek kamu butuh plugin spesifik (misal eslint-plugin-security), tetap pakai ESLint.
Checklist Setup Akhir
Sebelum mulai coding, pastikan ini sudah ada:
-
.nvmrcatau.node-versiondi root proyek -
.env.exampledengan semua key yang dibutuhkan -
.envdi.gitignore - Validasi env variables saat startup
-
tsconfig.jsondenganstrict: true - ESLint + Prettier terkonfigurasi
- Pre-commit hook aktif
-
README.mddengan instruksiGetting Startedyang jelas
Ini bukan overkill. Ini investasi 30 menit yang menghemat berjam-jam frustrasi di kemudian hari—terutama kalau ada orang lain (atau kamu sendiri 6 bulan ke depan) yang perlu onboarding ke proyek ini.
Kesimpulan
Nodejs development environment setup yang baik bukan soal pakai tool paling baru atau paling keren. Ini soal konsistensi: versi Node terkontrol, environment variables tervalidasi, kode terformat otomatis, dan dev environment semirip mungkin dengan production.
Langkah konkret untuk besok: kalau kamu belum pakai nvm atau fnm, install sekarang dan tambahkan .nvmrc ke semua proyek aktif kamu. Itu saja sudah menyelesaikan 60% masalah "works on my machine".
Kalau kamu mau setup yang lebih lengkap untuk proyek full-stack, cek juga artikel tentang konfigurasi monorepo Node.js dengan pnpm workspaces.