메인 콘텐츠로 건너뛰기
데이터베이스 연결 설정을 다룹니다. Sonamu는 PostgreSQL을 기본 데이터베이스로 사용하며, 환경별로 다른 데이터베이스 설정을 지원합니다.

기본 구조

import { defineConfig } from "sonamu";

export default defineConfig({
  database: {
    database: "pg",
    name: "mydb",
    defaultOptions: {
      connection: {
        host: "localhost",
        port: 5432,
        user: "postgres",
        password: "password",
      },
    },
    environments: {
      development: { /* ... */ },
      production: { /* ... */ },
    },
  },
  // ...
});

database

사용할 PostgreSQL 드라이버를 지정합니다. 타입: "pg" | "pgnative" (선택적) 기본값: "pg"
export default defineConfig({
  database: {
    database: "pg",  // 기본 pg 모듈 사용
    // ...
  },
});

pg vs pgnative

  • "pg": 순수 JavaScript로 구현된 PostgreSQL 드라이버 (권장)
    • 설치: pnpm add pg
    • 크로스 플랫폼 지원
    • 대부분의 경우 충분한 성능
  • "pgnative": C 바인딩을 사용하는 네이티브 드라이버
    • 설치: pnpm add pg-native
    • 더 빠른 성능 (특히 대량 데이터 처리)
    • 컴파일 필요, 플랫폼 의존성
특별한 성능 요구사항이 없다면 "pg"를 사용하세요. 설치와 배포가 간단합니다.

name

데이터베이스 이름을 지정합니다. 타입: string (필수)
export default defineConfig({
  database: {
    database: "pg",
    name: "ecommerce",  // 연결할 데이터베이스 이름
    // ...
  },
});
환경 변수 사용:
export default defineConfig({
  database: {
    database: "pg",
    name: process.env.DATABASE_NAME ?? "mydb",
    // ...
  },
});

defaultOptions

모든 환경에 공통으로 적용될 데이터베이스 설정입니다. Knex 설정 옵션을 사용합니다. 타입: DatabaseConfig (필수)
type DatabaseConfig = Omit<Knex.Config, "connection"> & {
  connection?: Knex.PgConnectionConfig;
};

connection 설정

데이터베이스 연결 정보를 설정합니다.
export default defineConfig({
  database: {
    database: "pg",
    name: "mydb",
    defaultOptions: {
      connection: {
        host: "localhost",       // 데이터베이스 호스트
        port: 5432,             // PostgreSQL 포트
        user: "postgres",       // 사용자 이름
        password: "password",   // 비밀번호
      },
    },
  },
});
환경 변수로 안전하게 관리:
export default defineConfig({
  database: {
    database: "pg",
    name: process.env.DATABASE_NAME ?? "mydb",
    defaultOptions: {
      connection: {
        host: process.env.DB_HOST ?? "localhost",
        port: Number(process.env.DB_PORT ?? 5432),
        user: process.env.DB_USER ?? "postgres",
        password: process.env.DB_PASSWORD,
      },
    },
  },
});
데이터베이스 비밀번호는 반드시 환경 변수로 관리하세요. 코드에 직접 작성하지 마세요!

추가 Knex 옵션

connection 외에도 다양한 Knex 옵션을 설정할 수 있습니다:
export default defineConfig({
  database: {
    database: "pg",
    name: "mydb",
    defaultOptions: {
      connection: { /* ... */ },
      
      // 커넥션 풀 설정
      pool: {
        min: 2,
        max: 10,
        acquireTimeoutMillis: 30000,
        idleTimeoutMillis: 30000,
      },
      
      // 쿼리 타임아웃
      acquireConnectionTimeout: 10000,
      
      // 디버그 모드
      debug: process.env.NODE_ENV === "development",
    },
  },
});

environments

환경별로 다른 데이터베이스 설정을 지정합니다. defaultOptions를 오버라이드합니다. 타입: (선택적)
environments?: {
  development?: DatabaseConfig;
  development_slave?: DatabaseConfig;
  production?: DatabaseConfig;
  production_slave?: DatabaseConfig;
  fixture?: DatabaseConfig;
  test?: DatabaseConfig;
}

환경별 설정 예시

export default defineConfig({
  database: {
    database: "pg",
    name: "mydb",
    defaultOptions: {
      connection: {
        host: "localhost",
        port: 5432,
        user: "postgres",
        password: "dev-password",
      },
    },
    environments: {
      // 개발 환경 (기본값 사용)
      development: {
        connection: {
          host: "localhost",
          port: 5432,
          user: "dev_user",
          password: "dev_password",
        },
      },
      
      // 프로덕션 환경
      production: {
        connection: {
          host: process.env.PROD_DB_HOST,
          port: Number(process.env.PROD_DB_PORT),
          user: process.env.PROD_DB_USER,
          password: process.env.PROD_DB_PASSWORD,
        },
        pool: {
          min: 5,
          max: 30,  // 프로덕션에서는 더 큰 풀
        },
      },
      
      // 테스트 환경
      test: {
        connection: {
          host: "localhost",
          port: 5432,
          user: "test_user",
          password: "test_password",
          database: "mydb_test",  // 별도의 테스트 DB
        },
      },
    },
  },
});

현재 환경 결정

Sonamu는 다음 순서로 현재 환경을 결정합니다:
  1. NODE_ENV 환경 변수
  2. 기본값: development
# 개발 환경
NODE_ENV=development pnpm dev

# 프로덕션 환경
NODE_ENV=production pnpm start

# 테스트 환경
NODE_ENV=test pnpm test

Slave DB 설정

읽기 전용 복제본(slave)을 사용하는 경우:
export default defineConfig({
  database: {
    database: "pg",
    name: "mydb",
    defaultOptions: { /* ... */ },
    environments: {
      production: {
        connection: {
          host: "master.db.example.com",
          port: 5432,
          user: "master_user",
          password: process.env.MASTER_DB_PASSWORD,
        },
      },
      production_slave: {
        connection: {
          host: "slave.db.example.com",
          port: 5432,
          user: "slave_user",
          password: process.env.SLAVE_DB_PASSWORD,
        },
      },
    },
  },
});
Slave DB는 읽기 전용 쿼리에 사용되어 마스터 DB의 부하를 분산시킵니다.

실전 예시

기본 로컬 개발 설정

import { defineConfig } from "sonamu";

export default defineConfig({
  database: {
    database: "pg",
    name: "myapp",
    defaultOptions: {
      connection: {
        host: "localhost",
        port: 5432,
        user: "postgres",
        password: "postgres",
      },
    },
  },
  // ...
});

환경 변수 활용 (권장)

import { defineConfig } from "sonamu";

export default defineConfig({
  database: {
    database: "pg",
    name: process.env.DATABASE_NAME ?? "myapp",
    defaultOptions: {
      connection: {
        host: process.env.DB_HOST ?? "localhost",
        port: Number(process.env.DB_PORT ?? 5432),
        user: process.env.DB_USER ?? "postgres",
        password: process.env.DB_PASSWORD,
      },
      pool: {
        min: 2,
        max: 10,
      },
    },
  },
  // ...
});
.env 파일:
DATABASE_NAME=myapp
DB_HOST=localhost
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=your-password-here

다중 환경 설정

import { defineConfig } from "sonamu";

const isDev = process.env.NODE_ENV === "development";
const isProd = process.env.NODE_ENV === "production";

export default defineConfig({
  database: {
    database: "pg",
    name: "ecommerce",
    defaultOptions: {
      connection: {
        host: process.env.DB_HOST ?? "localhost",
        port: Number(process.env.DB_PORT ?? 5432),
        user: process.env.DB_USER ?? "postgres",
        password: process.env.DB_PASSWORD,
      },
      debug: isDev,
    },
    environments: {
      development: {
        connection: {
          host: "localhost",
          port: 5432,
          user: "dev_user",
          password: "dev_password",
          database: "ecommerce_dev",
        },
        pool: {
          min: 2,
          max: 10,
        },
      },
      
      production: {
        connection: {
          host: process.env.PROD_DB_HOST,
          port: Number(process.env.PROD_DB_PORT),
          user: process.env.PROD_DB_USER,
          password: process.env.PROD_DB_PASSWORD,
          database: "ecommerce_prod",
        },
        pool: {
          min: 5,
          max: 30,
        },
        acquireConnectionTimeout: 60000,
      },
      
      production_slave: {
        connection: {
          host: process.env.PROD_SLAVE_DB_HOST,
          port: Number(process.env.PROD_SLAVE_DB_PORT),
          user: process.env.PROD_SLAVE_DB_USER,
          password: process.env.PROD_SLAVE_DB_PASSWORD,
          database: "ecommerce_prod",
        },
        pool: {
          min: 3,
          max: 20,
        },
      },
      
      test: {
        connection: {
          host: "localhost",
          port: 5432,
          user: "test_user",
          password: "test_password",
          database: "ecommerce_test",
        },
        pool: {
          min: 1,
          max: 5,
        },
      },
      
      fixture: {
        connection: {
          host: "localhost",
          port: 5432,
          user: "fixture_user",
          password: "fixture_password",
          database: "ecommerce_fixture",
        },
      },
    },
  },
  // ...
});

Docker Compose 환경

import { defineConfig } from "sonamu";

export default defineConfig({
  database: {
    database: "pg",
    name: "myapp",
    defaultOptions: {
      connection: {
        // Docker Compose의 서비스 이름 사용
        host: process.env.DB_HOST ?? "postgres",
        port: Number(process.env.DB_PORT ?? 5432),
        user: process.env.DB_USER ?? "postgres",
        password: process.env.DB_PASSWORD ?? "postgres",
      },
    },
  },
  // ...
});
docker-compose.yml:
services:
  postgres:
    image: postgres:16
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
    ports:
      - "5432:5432"
  
  api:
    build: .
    environment:
      DB_HOST: postgres  # 서비스 이름
      DB_PORT: 5432
      DB_USER: postgres
      DB_PASSWORD: postgres
      DATABASE_NAME: myapp

연결 테스트

데이터베이스 설정이 올바른지 확인하려면:
# 개발 서버 시작
pnpm dev

# 연결 성공 시 콘솔에 표시됨
# ✅ Database connected: myapp
연결 실패 시 일반적인 오류:
# 1. 비밀번호 오류
 password authentication failed for user "postgres"

# 2. 호스트 연결 실패
 connect ECONNREFUSED 127.0.0.1:5432

# 3. 데이터베이스가 존재하지 않음
 database "myapp" does not exist
연결 문제가 발생하면 PostgreSQL이 실행 중인지 확인하세요:
# macOS
brew services list

# Linux
systemctl status postgresql

# Docker
docker ps

주의사항

1. 비밀번호 보안

// ❌ 나쁜 예: 코드에 비밀번호 직접 작성
export default defineConfig({
  database: {
    defaultOptions: {
      connection: {
        password: "super-secret-password",  // 절대 금지!
      },
    },
  },
});

// ✅ 좋은 예: 환경 변수 사용
export default defineConfig({
  database: {
    defaultOptions: {
      connection: {
        password: process.env.DB_PASSWORD,
      },
    },
  },
});

2. 포트 번호 타입

// ❌ 나쁜 예: 문자열로 포트 지정
port: process.env.DB_PORT,  // "5432" (string)

// ✅ 좋은 예: 숫자로 변환
port: Number(process.env.DB_PORT ?? 5432),  // 5432 (number)

3. 커넥션 풀 크기

// 개발 환경: 작은 풀
pool: { min: 2, max: 10 }

// 프로덕션: 트래픽에 맞게 조정
pool: { min: 5, max: 30 }

// 테스트: 최소한으로
pool: { min: 1, max: 5 }

다음 단계

데이터베이스 설정을 완료했다면: