Nuxt에서 QR 코드를 생성하는 방법을 개발자 관점에서 정리합니다. qrcode 라이브러리를 사용해 클라이언트에서 QR 이미지를 만들고, 서버 API로 QR 코드 Data URL을 반환하는 실무형 예제를 제공합니다.

Nuxt로 QR 코드 생성하는 방법: qrcode 라이브러리 실무 소스코드 정리
Nuxt로 QR 코드 생성 기능을 구현할 때는 사용자가 입력한 URL이나 텍스트를 QR 이미지로 변환하고, 화면에 미리보기로 보여주거나 다운로드할 수 있게 만드는 방식이 가장 많이 사용됩니다. 이 글에서는 Nuxt에서 qrcode 라이브러리를 사용해 QR 코드를 생성하는 방법을 개발자 관점에서 정리하고, 바로 사용할 수 있는 소스코드까지 함께 설명합니다.
Nuxt는 Vue 기반의 풀스택 프레임워크이며, server/api 디렉터리를 통해 API 라우트를 만들 수 있습니다. 또한 qrcode 패키지는 브라우저와 서버 환경에서 QR 코드를 Data URL 형태로 생성할 수 있습니다.
Nuxt에서 QR 코드 생성 방식 선택하기
Nuxt에서 QR 코드를 생성하는 방식은 크게 두 가지로 나눌 수 있습니다.
단순히 사용자가 입력한 텍스트나 URL을 QR 코드로 보여주는 기능이라면 클라이언트 생성 방식이 가장 간단합니다. 반면 결제 링크, 쿠폰 코드, 회원 인증 URL처럼 서버에서 검증이 필요한 값이라면 서버 API 방식이 더 적합합니다.
패키지 설치
먼저 Nuxt 프로젝트에 qrcode 패키지를 설치합니다.
npm install qrcode
TypeScript를 사용하는 경우 타입 패키지도 함께 설치합니다.
npm install -D @types/qrcode
클라이언트에서 QR 코드 생성하기
가장 기본적인 방식은 Vue 컴포넌트에서 QRCode.toDataURL()을 호출해 QR 이미지 주소를 만드는 것입니다. toDataURL()은 QR 코드 이미지를 Data URI 문자열로 반환합니다.
pages/qr.vue
import QRCode from 'qrcode'
const qrText = ref('<a href=https://example.com')>https://example.com')</a>
const qrImage = ref('')
const errorMessage = ref('')
const generateQrCode = async () => {
errorMessage.value = ''
if (!qrText.value.trim()) {
errorMessage.value = 'QR 코드로 만들 텍스트 또는 URL을 입력해주세요.'
qrImage.value = ''
return
}
try {
qrImage.value = await QRCode.toDataURL(qrText.value, {
width: 300,
margin: 2,
errorCorrectionLevel: 'M',
color: {
dark: '#000000',
light: '#ffffff'
}
})
} catch (error) {
console.error(error)
errorMessage.value = 'QR 코드 생성 중 오류가 발생했습니다.'
}
}
const downloadQrCode = () => {
if (!qrImage.value) return
const link = document.createElement('a')
link.href = qrImage.value
link.download = 'qr-code.png'
link.click()
}
onMounted(() => {
generateQrCode()
})
Nuxt QR 코드 생성기
위 코드의 핵심은 다음 부분입니다.
qrImage.value = await QRCode.toDataURL(qrText.value, {
width: 300,
margin: 2,
errorCorrectionLevel: 'M'
})
qrText.value에는 QR 코드로 변환할 문자열이 들어갑니다. URL, 일반 텍스트, 이메일, 전화번호, 와이파이 접속 정보 등 문자열로 표현 가능한 값은 대부분 QR 코드로 만들 수 있습니다.
width는 생성되는 QR 이미지 크기입니다. 너무 작게 만들면 스캔이 잘 안 될 수 있으므로 일반적인 웹 화면에서는 250px 이상을 권장합니다.
margin은 QR 코드 주변 여백입니다. QR 코드는 주변 여백이 너무 좁으면 인식률이 떨어질 수 있으므로 최소한의 여백을 두는 것이 좋습니다.
errorCorrectionLevel은 QR 코드 오류 복원 수준입니다. 보통은 M 또는 Q 정도를 사용하면 무난합니다.
Nuxt 서버 API에서 QR 코드 생성하기
실무에서는 QR 코드로 만들 값이 서버에서 생성되는 경우가 많습니다. 예를 들어 다음과 같은 상황입니다.
- 로그인 인증용 일회성 URL
- 이벤트 쿠폰 코드
- 결제 페이지 URL
- 관리자에서 발급하는 초대 링크
- 출입 인증용 토큰 URL
이 경우 브라우저에서 QR 코드를 직접 만들기보다 Nuxt 서버 API에서 QR 코드를 생성한 뒤 프론트엔드로 전달하는 구조가 더 안전합니다.
Nuxt에서는 server/api 폴더에 파일을 만들면 API 라우트로 사용할 수 있습니다.
server/api/qr.post.ts
import QRCode from 'qrcode'
export default defineEventHandler(async (event) => {
const body = await readBody<{ text?: string }>(event)
if (!body.text || !body.text.trim()) {
throw createError({
statusCode: 400,
statusMessage: 'QR 코드로 만들 text 값이 필요합니다.'
})
}
try {
const qrImage = await QRCode.toDataURL(body.text, {
width: 300,
margin: 2,
errorCorrectionLevel: 'M',
color: {
dark: '#000000',
light: '#ffffff'
}
})
return {
success: true,
qrImage
}
} catch (error) {
console.error(error)
throw createError({
statusCode: 500,
statusMessage: 'QR 코드 생성 중 서버 오류가 발생했습니다.'
})
}
})
서버 API를 호출하는 Nuxt 페이지
pages/qr-api.vue
const qrText = ref('<a href=https://example.com')>https://example.com')</a>
const qrImage = ref('')
const isLoading = ref(false)
const errorMessage = ref('')
const generateQrCode = async () => {
errorMessage.value = ''
qrImage.value = ''
if (!qrText.value.trim()) {
errorMessage.value = 'QR 코드로 만들 텍스트 또는 URL을 입력해주세요.'
return
}
isLoading.value = true
try {
const response = await $fetch<{ success: boolean; qrImage: string }>('/api/qr', {
method: 'POST',
body: {
text: qrText.value
}
})
qrImage.value = response.qrImage
} catch (error) {
console.error(error)
errorMessage.value = 'QR 코드 생성 요청에 실패했습니다.'
} finally {
isLoading.value = false
}
}
const downloadQrCode = () => {
if (!qrImage.value) return
const link = document.createElement('a')
link.href = qrImage.value
link.download = 'qr-code.png'
link.click()
}
클라이언트 방식과 서버 API 방식 비교
| 구현 난이도 | 낮음 | 중간 |
| 서버 부하 | 거의 없음 | 요청마다 서버 처리 |
| 보안 처리 | 어려움 | 가능 |
| 인증 URL 생성 | 부적합 | 적합 |
| 단순 URL QR | 적합 | 가능 |
| 로그 저장 | 어려움 | 가능 |
| 대량 생성 | 부적합 | 별도 배치 처리 가능 |
단순 QR 코드 생성기라면 클라이언트 방식으로 충분합니다. 하지만 실무 서비스에서 QR 코드에 들어가는 값이 서버에서 검증되어야 한다면 서버 API 방식으로 구현하는 것이 좋습니다.
QR 코드 옵션 정리
qrcode 라이브러리에서 자주 사용하는 옵션은 다음과 같습니다.
{
width: 300,
margin: 2,
errorCorrectionLevel: 'M',
color: {
dark: '#000000',
light: '#ffffff'
}
}
옵션설명
| width | QR 코드 이미지 크기 |
| margin | QR 코드 외부 여백 |
| errorCorrectionLevel | 오류 복원 수준 |
| color.dark | QR 코드 점 색상 |
| color.light | 배경 색상 |
실무에서는 디자인 때문에 QR 코드 색상을 변경하는 경우가 있습니다. 다만 너무 연한 색상이나 배경과 대비가 낮은 색상은 스캔 실패율을 높일 수 있으므로 주의해야 합니다.
URL 유효성 검사 추가하기
QR 코드로 URL만 허용하고 싶다면 간단한 유효성 검사를 추가할 수 있습니다.
const isValidUrl = (value: string) => {
try {
const url = new URL(value)
return url.protocol === 'http:' || url.protocol === 'https:'
} catch {
return false
}
}
클라이언트 코드에 적용하면 다음과 같습니다.
if (!isValidUrl(qrText.value)) {
errorMessage.value = 'http 또는 https로 시작하는 올바른 URL을 입력해주세요.'
return
}
서버 API에서도 동일하게 검증하는 것이 좋습니다. 클라이언트 검증은 사용자 경험을 위한 것이고, 실제 보안 검증은 서버에서 다시 처리해야 합니다.
실무에서 자주 발생하는 문제
1. QR 코드가 생성되지 않는 경우
입력값이 비어 있거나 QRCode.toDataURL() 호출 중 예외가 발생한 경우입니다. 반드시 try...catch로 감싸고 사용자에게 오류 메시지를 보여주는 것이 좋습니다.
try {
qrImage.value = await QRCode.toDataURL(qrText.value)
} catch (error) {
console.error(error)
errorMessage.value = 'QR 코드 생성에 실패했습니다.'
}
2. QR 코드 다운로드가 안 되는 경우
Data URL이 생성되기 전에 다운로드 버튼을 클릭하면 다운로드할 이미지가 없습니다. 따라서 qrImage 값이 있을 때만 다운로드 버튼을 보여주는 방식이 안전합니다.
<button v-if="qrImage" @click="downloadQrCode">
다운로드
</button>
3. 모바일에서 QR 코드가 잘 안 읽히는 경우
QR 코드 크기가 너무 작거나, 여백이 부족하거나, 색상 대비가 낮은 경우입니다. 최소 250px 이상 크기로 만들고 배경은 흰색, QR 점은 검은색 또는 진한 색상으로 유지하는 것이 좋습니다.
composable로 QR 코드 생성 로직 분리하기
여러 페이지에서 QR 코드 생성 기능을 재사용하려면 composable로 분리하는 것이 좋습니다.
composables/useQrCode.ts
import QRCode from 'qrcode'
export const useQrCode = () => {
const qrImage = ref('')
const isLoading = ref(false)
const errorMessage = ref('')
const generateQrCode = async (text: string) => {
errorMessage.value = ''
qrImage.value = ''
if (!text.trim()) {
errorMessage.value = 'QR 코드로 만들 값이 필요합니다.'
return
}
isLoading.value = true
try {
qrImage.value = await QRCode.toDataURL(text, {
width: 300,
margin: 2,
errorCorrectionLevel: 'M',
color: {
dark: '#000000',
light: '#ffffff'
}
})
} catch (error) {
console.error(error)
errorMessage.value = 'QR 코드 생성 중 오류가 발생했습니다.'
} finally {
isLoading.value = false
}
}
return {
qrImage,
isLoading,
errorMessage,
generateQrCode
}
}
사용하는 페이지에서는 다음처럼 호출하면 됩니다.
const qrText = ref('<a href=https://example.com')>https://example.com')</a>
const {
qrImage,
isLoading,
errorMessage,
generateQrCode
} = useQrCode()
운영 환경에서 고려할 점
Nuxt QR 코드 생성 기능을 실제 서비스에 넣을 때는 단순히 이미지가 생성되는지만 보면 안 됩니다. QR 코드에 어떤 값이 들어가는지, 해당 값이 외부에 노출되어도 되는지, 만료 시간이 필요한지까지 함께 고려해야 합니다.
예를 들어 로그인 인증 QR 코드라면 다음과 같은 구조가 더 안전합니다.
1. 서버에서 일회성 토큰 생성
2. 토큰을 DB 또는 Redis에 저장
3. QR 코드에는 토큰이 포함된 URL만 삽입
4. 사용자가 QR 코드 스캔
5. 서버에서 토큰 유효성 검증
6. 사용 후 토큰 만료 처리
QR 코드 자체는 단순한 이미지입니다. 보안은 QR 코드 이미지가 아니라 QR 코드 안에 들어가는 URL과 서버 검증 로직에서 처리해야 합니다.
FAQ
Nuxt에서 QR 코드 생성은 클라이언트에서 하는 게 좋나요?
단순 URL이나 텍스트 QR 코드라면 클라이언트 생성 방식이 간단합니다. 하지만 인증, 결제, 쿠폰처럼 서버 검증이 필요한 값이라면 서버 API에서 생성하는 방식을 추천합니다.
QR 코드 이미지를 PNG로 다운로드할 수 있나요?
가능합니다. QRCode.toDataURL()로 생성한 Data URL을 a 태그의 href에 넣고 download 속성을 사용하면 PNG 파일로 저장할 수 있습니다.
QR 코드에 로고를 넣을 수 있나요?
기본 qrcode 패키지만으로는 중앙 로고 합성까지 자동 처리하지는 않습니다. 로고가 필요하다면 Canvas를 사용해 QR 이미지 위에 로고를 합성하거나, 별도 QR 커스터마이징 라이브러리를 검토하는 것이 좋습니다.
서버 API로 QR 코드를 만들면 장점이 있나요?
서버에서 QR 코드 값을 검증하거나, 생성 이력을 저장하거나, 인증 토큰을 발급하는 구조를 만들 수 있습니다. 실무 서비스에서는 이 점 때문에 서버 API 방식을 많이 사용합니다.
정리
Nuxt로 QR 코드 생성 기능을 만들 때는 먼저 QR 코드에 들어가는 값이 단순한 텍스트인지, 서버 검증이 필요한 값인지 구분해야 합니다. 단순한 QR 코드 생성기라면 클라이언트에서 qrcode 라이브러리의 toDataURL()을 사용하는 방식이 가장 빠릅니다. 반면 인증 URL, 쿠폰 코드, 결제 링크처럼 중요한 값을 다룬다면 Nuxt 서버 API에서 QR 코드를 생성하고 검증 로직을 함께 구성하는 것이 좋습니다.
Nuxt QR 코드 생성 기능은 구현 자체는 어렵지 않지만, 실무에서는 다운로드, 모바일 스캔 품질, URL 검증, 보안 토큰 만료 처리까지 함께 고려해야 안정적으로 운영할 수 있습니다.
'실무개발' 카테고리의 다른 글
| Nuxt에서 이미지 압축하는 방법: 브라우저 기반 JPG PNG WEBP 압축 구현 (0) | 2026.07.02 |
|---|---|
| Nuxt로 PDF 합치기 도구 만들기: 서버 업로드 없이 브라우저에서 PDF 병합 구현하기 (0) | 2026.06.30 |
| Nuxt3로 제비뽑기 웹 서비스를 만든 이유와 랜덤 추첨 기능 구현 방법 (0) | 2026.06.30 |
| 워드프레스 플러그인 제작하기: 숏코드, 관리자 설정, iframe 위젯까지 직접 구현하는 방법 (0) | 2026.06.21 |
| Docker로 워드프레스 설치하고 알뜰폰 위젯 플러그인 만들기 (0) | 2026.06.20 |
