Cursor는 AI 기반 코드 편집기로, VS Code를 기반으로 만들어진 차세대 개발 도구입니다. GPT-4와 Claude를 활용하여 코드 작성, 리팩토링, 디버깅을 지원하며, 자연어로 코드를 생성하고 전체 코드베이스를 이해하는 능력을 갖추고 있습니다. 이 튜토리얼에서는 실제 프로젝트를 만들면서 Cursor의 강력한 기능을 배워봅니다.
1. Cursor 시작하기
1.1 설치 및 초기 설정
Step 1: Cursor 다운로드
- cursor.sh 접속
- 운영체제에 맞는 버전 다운로드 (Windows/Mac/Linux)
- 설치 프로그램 실행
Step 2: 계정 생성
- Cursor 실행
- 이메일 또는 GitHub 계정으로 가입
- 무료 플랜 시작 (월 2000회 요청)
Step 3: VS Code 확장 기능 가져오기
Cursor는 VS Code 설정과 확장 기능을 자동으로 가져올 수 있습니다.
Cmd/Ctrl + Shift + P > "Cursor: Import VS Code Settings"
1.2 Cursor의 핵심 기능
- Cmd+K (Ctrl+K): AI 코드 생성 및 편집
- Cmd+L (Ctrl+L): AI 채팅 창 열기
- Cmd+Shift+L: 코드베이스 전체 검색
- Tab: AI 자동완성 수락
- @-mentions: 특정 파일이나 문서 참조
1.3 AI 모델 설정
Settings (Cmd/Ctrl + ,) > Cursor Settings
- Primary Model: GPT-4, Claude 3.5 Sonnet 중 선택
- Auto-completion: 활성화 권장
- Privacy Mode: 필요시 활성화
2. 실전 프로젝트: React Todo 앱 만들기
이제 Cursor를 사용하여 실제 프로젝트를 만들어봅시다. React와 TypeScript를 사용한 Todo 애플리케이션을 처음부터 끝까지 구현합니다.
2.1 프로젝트 초기화
Step 1: 새 프로젝트 생성
Cursor 터미널에서 다음 명령 실행:
npm create vite@latest todo-app -- --template react-ts
cd todo-app
npm install
Step 2: Cursor에서 프로젝트 열기
File > Open Folder > todo-app 선택
2.2 AI로 컴포넌트 생성하기
Step 1: Todo 타입 정의하기
새 파일 생성: src/types/todo.ts
Cmd+K (Ctrl+K)를 누르고 다음 프롬프트 입력:
Todo 애플리케이션을 위한 TypeScript 타입을 정의해주세요.
다음 속성을 포함:
- id (string)
- title (string)
- completed (boolean)
- createdAt (Date)
- priority (high/medium/low)
생성된 코드:
// src/types/todo.ts
export type Priority = 'high' | 'medium' | 'low';
export interface Todo {
id: string;
title: string;
completed: boolean;
createdAt: Date;
priority: Priority;
}
export interface TodoState {
todos: Todo[];
filter: 'all' | 'active' | 'completed';
}
Step 2: Todo 아이템 컴포넌트
새 파일 생성: src/components/TodoItem.tsx
Cmd+L (Ctrl+L)로 채팅 열고:
@todo.ts 타입을 사용하는 TodoItem 컴포넌트를 만들어주세요.
기능:
- Todo 항목 표시
- 완료 체크박스
- 삭제 버튼
- Priority badge (색상별)
- Tailwind CSS 사용
생성된 코드:
// src/components/TodoItem.tsx
import React from 'react';
import { Todo } from '../types/todo';
interface TodoItemProps {
todo: Todo;
onToggle: (id: string) => void;
onDelete: (id: string) => void;
}
export const TodoItem: React.FC = ({
todo,
onToggle,
onDelete
}) => {
const priorityColors = {
high: 'bg-red-100 text-red-800',
medium: 'bg-yellow-100 text-yellow-800',
low: 'bg-green-100 text-green-800',
};
return (
onToggle(todo.id)}
className="w-5 h-5 text-blue-600 rounded focus:ring-2 focus:ring-blue-500"
/>
{todo.title}
{todo.priority}
{new Date(todo.createdAt).toLocaleDateString('ko-KR')}
);
};
2.3 상태 관리 구현
Step 1: Custom Hook 생성
새 파일: src/hooks/useTodos.ts
AI 프롬프트:
@todo.ts 타입을 사용하는 useTodos 커스텀 훅을 만들어주세요.
기능:
- Todo 추가, 삭제, 토글
- LocalStorage에 자동 저장
- 필터링 (전체/활성/완료)
- 정렬 (날짜, 우선순위)
생성된 코드:
// src/hooks/useTodos.ts
import { useState, useEffect } from 'react';
import { Todo, TodoState, Priority } from '../types/todo';
const STORAGE_KEY = 'todos';
export const useTodos = () => {
const [state, setState] = useState(() => {
const saved = localStorage.getItem(STORAGE_KEY);
return saved
? JSON.parse(saved)
: { todos: [], filter: 'all' as const };
});
// LocalStorage에 자동 저장
useEffect(() => {
localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
}, [state]);
const addTodo = (title: string, priority: Priority = 'medium') => {
const newTodo: Todo = {
id: crypto.randomUUID(),
title,
completed: false,
createdAt: new Date(),
priority,
};
setState(prev => ({
...prev,
todos: [...prev.todos, newTodo],
}));
};
const toggleTodo = (id: string) => {
setState(prev => ({
...prev,
todos: prev.todos.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
),
}));
};
const deleteTodo = (id: string) => {
setState(prev => ({
...prev,
todos: prev.todos.filter(todo => todo.id !== id),
}));
};
const setFilter = (filter: TodoState['filter']) => {
setState(prev => ({ ...prev, filter }));
};
const getFilteredTodos = () => {
switch (state.filter) {
case 'active':
return state.todos.filter(todo => !todo.completed);
case 'completed':
return state.todos.filter(todo => todo.completed);
default:
return state.todos;
}
};
const sortByPriority = (todos: Todo[]) => {
const priorityOrder = { high: 0, medium: 1, low: 2 };
return [...todos].sort((a, b) =>
priorityOrder[a.priority] - priorityOrder[b.priority]
);
};
return {
todos: getFilteredTodos(),
filter: state.filter,
addTodo,
toggleTodo,
deleteTodo,
setFilter,
sortByPriority,
stats: {
total: state.todos.length,
active: state.todos.filter(t => !t.completed).length,
completed: state.todos.filter(t => t.completed).length,
},
};
};
2.4 메인 App 컴포넌트
App.tsx 수정
기존 내용을 선택하고 Cmd+K:
@useTodos @TodoItem 을 사용하는 완전한 Todo 애플리케이션을 만들어주세요.
포함할 기능:
- 새 Todo 추가 폼 (title, priority 선택)
- Todo 리스트 표시
- 필터 버튼 (전체/활성/완료)
- 통계 표시
- Tailwind CSS로 모던한 디자인
생성된 코드:
// src/App.tsx
import React, { useState } from 'react';
import { TodoItem } from './components/TodoItem';
import { useTodos } from './hooks/useTodos';
import { Priority } from './types/todo';
function App() {
const [title, setTitle] = useState('');
const [priority, setPriority] = useState('medium');
const {
todos,
filter,
addTodo,
toggleTodo,
deleteTodo,
setFilter,
sortByPriority,
stats
} = useTodos();
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (title.trim()) {
addTodo(title, priority);
setTitle('');
setPriority('medium');
}
};
const sortedTodos = sortByPriority(todos);
return (
{/* Header */}
My Todo List
Stay organized and productive
{/* Stats */}
{stats.total}
Total
{stats.active}
Active
{stats.completed}
Completed
{/* Add Todo Form */}
{/* Filter Buttons */}
{(['all', 'active', 'completed'] as const).map((f) => (
))}
{/* Todo List */}
{sortedTodos.length === 0 ? (
No todos yet!
Add one above to get started
) : (
sortedTodos.map((todo) => (
))
)}
);
}
export default App;
2.5 Tailwind CSS 설정
터미널에서 실행:
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
tailwind.config.js 수정 (Cmd+K 사용):
/** @type {import('tailwindcss').Config} */
export default {
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
src/index.css에 Tailwind 추가:
@tailwind base;
@tailwind components;
@tailwind utilities;
3. Cursor의 고급 기능 활용
3.1 코드 리팩토링
코드 블록을 선택하고 Cmd+K:
이 코드를 리팩토링해서 성능을 개선하고 가독성을 높여주세요
3.2 테스트 코드 생성
함수를 선택하고 Cmd+L:
@useTodos.ts 의 addTodo 함수에 대한 유닛 테스트를 Vitest로 작성해주세요
생성된 테스트:
// src/hooks/useTodos.test.ts
import { renderHook, act } from '@testing-library/react';
import { describe, it, expect, beforeEach } from 'vitest';
import { useTodos } from './useTodos';
describe('useTodos', () => {
beforeEach(() => {
localStorage.clear();
});
it('should add a new todo', () => {
const { result } = renderHook(() => useTodos());
act(() => {
result.current.addTodo('Test todo', 'high');
});
expect(result.current.todos).toHaveLength(1);
expect(result.current.todos[0].title).toBe('Test todo');
expect(result.current.todos[0].priority).toBe('high');
expect(result.current.todos[0].completed).toBe(false);
});
it('should toggle todo completion', () => {
const { result } = renderHook(() => useTodos());
act(() => {
result.current.addTodo('Test todo');
});
const todoId = result.current.todos[0].id;
act(() => {
result.current.toggleTodo(todoId);
});
expect(result.current.todos[0].completed).toBe(true);
});
it('should delete a todo', () => {
const { result } = renderHook(() => useTodos());
act(() => {
result.current.addTodo('Test todo');
});
const todoId = result.current.todos[0].id;
act(() => {
result.current.deleteTodo(todoId);
});
expect(result.current.todos).toHaveLength(0);
});
it('should persist todos in localStorage', () => {
const { result } = renderHook(() => useTodos());
act(() => {
result.current.addTodo('Persistent todo');
});
const saved = localStorage.getItem('todos');
expect(saved).toBeTruthy();
const parsed = JSON.parse(saved!);
expect(parsed.todos).toHaveLength(1);
});
});
3.3 문서화
함수 위에 커서를 두고 Cmd+K:
이 함수에 JSDoc 주석을 추가해주세요
3.4 버그 찾기
AI 채팅에서:
@App.tsx 를 검토하고 잠재적인 버그나 성능 문제를 찾아주세요
4. Cursor 생산성 팁
4.1 @-mentions 마스터하기
- @파일명: 특정 파일 참조
- @폴더: 전체 폴더 컨텍스트
- @web: 웹 검색 결과 포함
- @docs: 프로젝트 문서 참조
- @codebase: 전체 코드베이스 검색
4.2 효과적인 프롬프트 작성
나쁜 프롬프트:
버튼 만들어줘
좋은 프롬프트:
@TodoItem.tsx 의 삭제 버튼과 동일한 스타일의 편집 버튼을 추가해주세요.
Heroicons의 PencilIcon을 사용하고,
클릭 시 onEdit 콜백을 호출하도록 구현해주세요.
4.3 키보드 단축키 활용
| 단축키 | 기능 |
|---|---|
Cmd+K |
인라인 AI 편집 |
Cmd+L |
AI 채팅 열기 |
Tab |
AI 제안 수락 |
Cmd+Shift+L |
코드베이스 검색 |
Cmd+I |
새 파일 생성 (AI와 함께) |
5. 프로젝트 완성 및 배포
5.1 프로덕션 빌드
npm run build
5.2 Vercel 배포
Step 1: Vercel CLI 설치
npm i -g vercel
Step 2: 배포
vercel
AI에게 배포 설정 도움 받기:
@Cmd+L: Vercel에 이 프로젝트를 배포하기 위한 vercel.json 설정 파일을 만들어주세요
5.3 GitHub Actions CI/CD
AI에게 요청:
GitHub Actions로 자동 배포 워크플로우를 만들어주세요.
- main 브랜치에 push할 때 실행
- 린트, 테스트, 빌드 단계 포함
- Vercel에 자동 배포
6. 일반적인 문제 해결
문제 1: AI가 잘못된 코드 생성
해결:
- 더 구체적인 컨텍스트 제공 (@mentions 활용)
- "다시 생성해줘, 이번엔 [구체적 요구사항]" 요청
- 생성된 코드 선택 후 "이 코드의 문제점 찾아줘" 요청
문제 2: 자동완성이 느림
해결:
- Settings > Cursor Settings > "Faster completions" 활성화
- 큰 파일은 부분적으로 작업
- 불필요한 파일은 .cursorignore에 추가
문제 3: API 한도 초과
해결:
- Pro 플랜으로 업그레이드 (월 $20, 무제한 요청)
- 자체 API 키 사용 (Settings > Models)
- 불필요한 자동완성 비활성화
7. Cursor vs 다른 AI 코딩 도구
| 도구 | 장점 | 단점 |
|---|---|---|
| Cursor | 전체 코드베이스 이해, 강력한 AI 채팅 | 유료 플랜 필요 (대량 사용 시) |
| GitHub Copilot | VS Code 통합, 안정성 | 컨텍스트 이해 제한적 |
| Codeium | 무료, 다양한 에디터 지원 | AI 품질이 상대적으로 낮음 |
| Tabnine | 프라이버시 중심, 로컬 모델 | 온라인 모델 대비 성능 낮음 |
8. 고급 활용 사례
8.1 레거시 코드 마이그레이션
@old-component.js 를 TypeScript와 React Hooks로 마이그레이션해주세요.
- Class 컴포넌트 → Function 컴포넌트
- PropTypes → TypeScript interfaces
- this.state → useState
- 모든 타입 정의 추가
8.2 API 클라이언트 자동 생성
다음 OpenAPI 스펙을 기반으로 TypeScript API 클라이언트를 생성해주세요:
@api-spec.yaml
axios를 사용하고, 모든 엔드포인트에 대한 타입 안전한 함수를 만들어주세요.
8.3 성능 최적화
@App.tsx 의 성능을 분석하고 다음 최적화를 적용해주세요:
1. 불필요한 리렌더링 방지 (React.memo, useMemo, useCallback)
2. 코드 스플리팅 (React.lazy)
3. 번들 크기 최적화
"Cursor는 단순한 자동완성 도구가 아닙니다. AI 페어 프로그래머와 함께 일하는 것과 같습니다."
9. 모범 사례
9.1 프롬프트 작성 가이드
- 구체적이고 명확한 요구사항 제시
- 관련 파일과 컨텍스트 참조 (@mentions)
- 예상 출력 형식 명시
- 코딩 스타일과 컨벤션 명시
- 단계별로 작업 분할
9.2 코드 품질 유지
- AI 생성 코드는 항상 검토
- 테스트 코드 작성 필수
- 타입 안전성 확보
- 린터와 포매터 설정
- 코드 리뷰 프로세스 유지
마치며
Cursor를 사용하면 코딩 속도가 2-3배 빠라집니다. 하지만 AI는 도구일 뿐이며, 최종 결정은 개발자가 내려야 합니다. 이 튜토리얼에서 배운 기법들을 실제 프로젝트에 적용하면서 자신만의 AI 코딩 워크플로우를 만들어보세요.
Happy Coding with AI!
참고 자료
- Cursor Documentation - 공식 문서
- Cursor GitHub - 기능 요청 및 이슈
- Cursor Directory - 프롬프트 템플릿 모음
- Cursor YouTube - 비디오 튜토리얼
- Cursor Discord - 커뮤니티