AI로 프로젝트 보일러플레이트 만들기: 고정 템플릿과 생성 범위 나누기, 설치 전 의존성 점검
존재하지 않는 패키지, 오래된 패키지, peer 의존성 충돌을 npm install 전에 걸러내는 순서

핵심 요약
- 폴더 구조·설정·허용 패키지 목록은 고정하고, 도메인 코드만 AI에 생성시킨다.
- 코드 생성 LLM은 존재하지 않는 패키지 이름을 만들 수 있으므로 의존성은 설치 전에 레지스트리에서 확인한다.
- 실제로 있는 패키지도 오래 배포가 없으면 peer 의존성이 맞지 않을 수 있다.
- --legacy-peer-deps로 충돌을 덮지 말고, min-release-age로 너무 새 버전 설치를 막는 방법을 검토한다.
새 프로젝트의 폴더 구조, 설정 파일, 기본 라우트를 AI 코딩 도구로 만들면 몇 분 만에 초안이 나온다. 이때 가장 조심할 부분은 코드보다 package.json이다. AI가 그럴듯한 이름의 패키지를 지어내거나, 오래전에 관리가 멈춘 패키지를 고르거나, 서로 맞지 않는 버전을 섞는 일이 있다. 이 글은 고정할 부분과 생성시킬 부분을 나누는 기준을 정리하고, 생성된 의존성을 설치 전에 점검하는 방법을 실제 실행 결과로 보여 준다.
고정 템플릿과 AI 생성의 경계
| 고정(템플릿·규칙 파일) | AI에 생성시킬 것 |
|---|---|
| 폴더 구조, 실행·테스트 스크립트 | 엔드포인트, 도메인 모델, 검증 스키마 |
| 린트·포맷·타입 설정 | 샘플 데이터, 초기 테스트 케이스 |
| 허용 패키지 목록과 버전 범위 | 목록 안에서의 패키지 조합 |
| .env.example의 키 이름 | 키를 읽는 설정 코드 |
핵심은 허용 패키지 목록을 고정 쪽에 두는 것이다. 요청할 때 "아래 목록 밖의 패키지는 추가하지 말고, 필요하면 이유와 함께 제안만 하라"고 적고, 규칙 파일에도 같은 내용을 둔다. 규칙 파일 작성은 Cursor Rules 작성법을 참고한다.
왜 설치 전에 의존성을 확인해야 하나
코드 생성 LLM이 존재하지 않는 패키지 이름을 만들어 내는 현상을 분석한 연구는 16개 모델로 만든 코드 샘플 57만 6천 개를 조사해, 상용 모델은 평균 5.2% 이상, 오픈소스 모델은 평균 21.7%의 패키지 환각 비율을 보였고 서로 다른 환각 패키지 이름이 20만 5천여 개였다고 보고했다. 환각된 이름을 누군가 먼저 등록해 악성 코드를 올리면, npm install이 그 코드를 그대로 받아 설치 스크립트까지 실행할 수 있다. 그래서 확인은 설치 전에 해야 한다.
설치 전 점검 스크립트
아래 스크립트는 패키지를 설치하지 않고 npm 레지스트리 메타데이터만 조회한다. 레지스트리에 없는 패키지, 생성된 지 90일이 안 된 패키지, 주간 다운로드가 1,000회 미만인 패키지, 마지막 배포가 2년을 넘은 패키지를 확인 대상으로 표시한다. 다운로드 수는 npm의 다운로드 수 API를 쓴다.
// 사용법: node check-deps.mjs package.json
// AI가 만든 package.json의 의존성이 npm 레지스트리에 실제로 있는지, 너무 최근에 만들어졌거나
// 다운로드가 거의 없는 패키지는 아닌지 설치 전에 확인한다(설치하지 않고 메타데이터만 조회).
import { readFileSync } from 'node:fs';
const pkg = JSON.parse(readFileSync(process.argv[2], 'utf8'));
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
const DAY = 864e5;
let problems = 0;
for (const name of Object.keys(deps)) {
const res = await fetch(`https://registry.npmjs.org/${name.replace('/', '%2F')}`, { signal: AbortSignal.timeout(10000) });
if (res.status === 404) { problems++; console.log(`없음 ${name} — 레지스트리에 존재하지 않음 (환각 의심)`); continue; }
const meta = await res.json();
const ageDays = Math.floor((Date.now() - new Date(meta.time.created)) / DAY);
const dl = await fetch(`https://api.npmjs.org/downloads/point/last-week/${name}`).then((r) => r.json()).catch(() => ({}));
const weekly = dl.downloads ?? 0;
const latest = meta['dist-tags']?.latest;
const staleDays = Math.floor((Date.now() - new Date(meta.time[latest])) / DAY);
// 새로 만들어졌거나(이름 선점 의심), 거의 안 쓰이거나, 2년 넘게 배포가 없는 패키지는 확인 대상으로 둔다.
const warn = ageDays < 90 || weekly < 1000 || staleDays > 730;
if (warn) problems++;
console.log(`${warn ? '확인' : 'OK '} ${name}@${latest} — 생성 ${ageDays}일 전, 마지막 배포 ${staleDays}일 전, 주간 다운로드 ${weekly.toLocaleString()}`);
}
console.log(problems ? `\n확인 필요 ${problems}건 — 설치 전에 공식 문서·저장소를 확인하세요.` : '\n모든 의존성 확인');
process.exitCode = problems ? 1 : 0;
점검 대상은 AI가 만들어 낸 것처럼 꾸민 예시 package.json이다. express-zod-api-validator-middleware는 그럴듯하게 지은 이름이고, 나머지는 실제 패키지다.
{
"name": "orders-api",
"private": true,
"type": "module",
"dependencies": {
"express": "^5.1.0",
"zod": "^4.0.0",
"zod-express-middleware": "^1.4.0",
"express-zod-api-validator-middleware": "^2.0.0"
},
"devDependencies": {
"vitest": "^3.0.0"
}
}
$ node check-deps.mjs package.json
OK [email protected] — 생성 5760일 전, 마지막 배포 309일 전, 주간 다운로드 169,483,150
OK [email protected] — 생성 2404일 전, 마지막 배포 23일 전, 주간 다운로드 387,371,526
확인 [email protected] — 생성 1941일 전, 마지막 배포 1903일 전, 주간 다운로드 48,734
없음 express-zod-api-validator-middleware — 레지스트리에 존재하지 않음 (환각 의심)
OK [email protected] — 생성 1769일 전, 마지막 배포 7일 전, 주간 다운로드 142,142,023
확인 필요 2건 — 설치 전에 공식 문서·저장소를 확인하세요.
"확인"으로 표시된 패키지를 열어 보면
zod-express-middleware는 실제로 있고 주간 다운로드도 4만 8천 회가 넘지만, 마지막 배포가 약 5년 전이다. 레지스트리에서 1.4.0의 peerDependencies를 확인하면 zod: ^3.2.0, express: ^4.17.1이다. 이 프로젝트는 zod 4와 express 5를 쓰므로 맞지 않는다. 환각 패키지를 뺀 뒤 스크립트를 실행하지 않는 --ignore-scripts로 설치를 시험하면 npm이 충돌을 알려 준다.
$ npm install --dry-run --ignore-scripts --no-audit --no-fund
npm error code ERESOLVE
npm error ERESOLVE unable to resolve dependency tree
npm error Found: [email protected]
npm error Could not resolve dependency:
npm error peer express@"^4.17.1" from [email protected]
npm error Fix the upstream dependency conflict, or retry this command with --force or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution.
오류 메시지가 --legacy-peer-deps를 대안으로 보여 주지만, npm 문서는 이 옵션이 peerDependencies 계약을 강제하지 않으므로 권장하지 않는다고 적는다. AI 도구가 설치 오류를 고치려고 이 옵션을 붙이는 제안을 하면 그대로 받지 말고, 패키지 자체를 바꾸거나 직접 구현할지 판단한다. 이 경우 Express 미들웨어 몇 줄로 Zod 검증을 직접 붙이는 편이 의존성 하나를 줄인다.
npm의 min-release-age로 너무 새 버전 막기
npm 문서에 따르면 min-release-age를 설정하면 지정한 일수보다 오래전에 공개된 버전만으로 의존성 트리를 만들고, 맞는 버전이 없으면 오류로 멈춘다. 방금 등록된 악성 패키지나 탈취된 계정이 올린 새 버전을 설치하는 위험을 줄이는 설정이다. 이 글을 쓰는 시점에 7일 전 배포된 vitest 5.0.3을 30일 기준으로 요청하면 설치를 거부한다.
$ npm install --dry-run --ignore-scripts --min-release-age=30 # vitest@^5.0.3
npm error code ETARGET
npm error notarget No matching version found for vitest@^5.0.3 with a date before 2026. 9. 7. PM 11:34:44.
팀 저장소의 .npmrc에 min-release-age=7처럼 두면 모든 설치에 적용된다. 보안 패치처럼 새 버전이 급히 필요할 때 막히는 부작용이 있으므로, 문서의 예외 설정(min-release-age-exclude)과 함께 정한다.
생성부터 첫 커밋까지 순서
- 고정 템플릿과 허용 패키지 목록을 요청에 함께 준다.
- 생성된 파일 목록과 각 파일의 역할을 먼저 요약하게 한다.
- 설치 전에 의존성 점검 스크립트를 실행하고, 없음·확인 항목을 해결한다.
--ignore-scripts로 설치를 시험한 뒤 정상 설치한다.- 린트·타입 검사·테스트가 모두 통과한 상태로 첫 커밋을 만든다. 커밋 전 자동 검사는 ESLint·Prettier·tsc 자동화에서 다룬다.
초보자가 자주 실수하는 포인트
- AI가 만든 package.json을 확인 없이 바로 npm install 한다.
- 설치 오류를 --legacy-peer-deps나 --force로 넘긴다.
- 다운로드 수만 보고 마지막 배포 시점과 peer 의존성을 확인하지 않는다.
- 허용 패키지 목록 없이 생성을 요청해 매번 다른 라이브러리가 들어온다.
체크리스트
- 요청에 고정 템플릿과 허용 패키지 목록을 넣었다.
- 의존성 점검 스크립트에서 없음·확인 항목이 없다.
- peer 의존성 충돌 없이 --ignore-scripts 설치가 된다.
- .npmrc의 min-release-age 사용 여부를 정했다.
- 린트·타입·테스트 통과 후 첫 커밋을 만들었다.
자주 묻는 질문
패키지가 레지스트리에 있으면 안전한가요?
존재는 첫 단계일 뿐입니다. 이 글의 예처럼 존재하더라도 관리가 멈춰 현재 버전과 맞지 않을 수 있고, 최근에 등록된 이름 선점 패키지일 수도 있습니다. 생성 시점, 마지막 배포, 다운로드 수, 저장소 링크를 함께 확인합니다.
npm install --dry-run은 패키지를 실행하나요?
--dry-run은 실제로 설치하지 않고 의존성 트리만 계산합니다. 이 글에서는 혹시 모를 설치 스크립트 실행을 막기 위해 --ignore-scripts도 함께 붙였습니다.
참고 자료 · 검증 기준
- Spracklen et al. — We Have a Package for You! A Comprehensive Analysis of Package Hallucinations by Code Generating LLMs
- npm Docs — config (legacy-peer-deps, min-release-age)
- npm registry — Download counts API
위 자료와 내용을 대조한 날짜: . 도구·서비스 정책은 이후 바뀔 수 있으므로 적용 전 공식 문서를 다시 확인하세요.
이 글은 실제 실무 환경 테스트 및 검증된 기술 자료를 바탕으로 작성되었으며, 환경 변화에 따라 지속적으로 갱신됩니다.