- 2026.07.29 Apps Script 프로젝트가 늘어나면 반드시 망가지는 것들
- 2026.07.16 매일 돌던 Apps Script 트리거가 갑자기 멈추는 이유
- 2026.07.15 브라우저 저장소에 고객정보 넣으면 생기는 문제
- 2026.07.07 브라우저가 내 데이터를 버릴 때: 초록 체크가 거짓말을 한다
- 2026.07.07 설치됨 ≠ 작동함: 백업 트리거가 한 번도 안 돌았다
- 2026.07.07 GAS엔 점진 배포가 없다: '맞는' 검사 하나가 전 사용자를 잠근다
- 2026.07.07 시트가 텍스트를 날짜로 바꾼다: '2026-06'이 완료를 영영 막을 때
- 2026.06.18 여러 사람이 한 시트에 쓰는 점검 앱: 동시성·중복·내보내기 설계
- 2026.06.12 셀을 한 칸씩 읽지 마라: 서비스 호출이 진짜 비용이다
- 2026.06.11 시트 셀에 JSON·이미지를 통째로 넣으면 터진다 지금 보는 글
- 2026.06.10 웹앱 배포 설정 하나가 보안 모델을 정한다: Execute as / 접근 권한
- 2026.06.09 GAS 6분 실행 한도: 멈추기 전에 끊어서 재개하라
- 2026.06.08 PropertiesService는 데이터베이스가 아니다: 9KB의 벽
- 2026.06.07 모바일에서 화면을 이미지로 저장할 때 멈추는 진짜 이유
- 2026.06.06 동시에 같은 시트를 쓰면 깨진다: LockService와 30 동시 실행 천장
- 2026.06.05 재배포할 때마다 주소가 바뀌면 안 된다: /exec URL 고정
- 2026.06.04 외부 호출은 가끔 실패한다: 지수 백오프와 재시도 예산
- 2026.06.03 HtmlService 앱은 껍데기 먼저: 비동기 로드와 모바일 뒤로가기
- 2026.06.02 GAS를 졸업해야 할 때: 한계 신호와 외부 DB 이전
- 2026.06.01 GAS에 지능과 엔진룸을 더하기: Vertex AI와 Cloud Run
시트 셀에 JSON·이미지를 통째로 넣으면 터진다
구글 시트 셀은 5만 자에서 막힌다. 사진·서명을 data URL로 기록 행에 넣으면 저장이 깨진다. 셀에는 메타데이터만 남겨라.
셀 하나에 들어가는 텍스트는 5만 자가 한계다. 사진이나 서명을 data URL(data:image/png;base64,...)로 만들어 기록 행에 그대로 넣으면, 한 장만으로 수십 KB에서 수 MB가 되어 이 한계를 바로 넘는다. 저장은 조용히 잘리거나 실패한다.
왜 중요한가
현장 점검앱에서 한 행에 사진 여러 장과 서명을 함께 저장하려다 막히면, 그날 입력한 기록이 통째로 유실된다. 에러도 명확하지 않아 원인을 찾는 데 시간이 걸린다. 비용은 “다시 점검하러 가는 출장”이다.
정답: 바이너리는 분리, 셀에는 경로만
기록 행에는 메타데이터와 파일 ID만 저장한다. 바이너리는 Drive에 파일로 두고, 셀에는 fileId만 남긴다.
// 나쁨: data URL을 기록에 직접 저장 → 5만 자 초과
record.photo = "data:image/jpeg;base64,/9j/4AAQ...";
// 좋음: 파일은 Drive에, 셀에는 id와 메타만
function savePhoto(base64, mime) {
const blob = Utilities.newBlob(Utilities.base64Decode(base64), mime, "photo.jpg");
const file = DriveApp.getFolderById(FOLDER_ID).createFile(blob);
return { fileId: file.getId(), bytes: blob.getBytes().length };
}
바이너리(data URL)는 화면에서 export할 때만 쓰는 export-only 상태로 두고, 저장 모델에는 절대 넣지 않는다.
같이 걸리는 함정 두 개
1) 수식 주입. =, +, -, @로 시작하는 사용자 입력은 시트에서 수식으로 해석된다. 저장 전에 '를 앞에 붙여 막는다.
function escapeFormula(v) {
return /^[=+\-@]/.test(String(v)) ? "'" + v : v;
}
2) JSON 직렬화. JSON.stringify()는 Date, Map, Set, undefined, NaN을 안전하게 복원하지 못한다. 날짜는 ISO 문자열로 저장하거나 replacer/reviver를 명시한다.
깊이: Properties도 같은 함정
PropertiesService는 값 하나당 9KB 한계다. 커서·작은 설정·idempotency key 정도만 두는 저장소이지 데이터베이스가 아니다. 9KB를 넘을 수 있는 상태는 Sheet, Drive JSON blob, CacheService, 외부 DB 중 하나로 설계한다.
큰 것은 셀 밖에, 셀에는 가리키는 값만. 바이너리는 Drive에 두고 기록 행에는 fileId와 메타데이터만 남긴다.
자주 묻는 질문
- 구글 시트 셀의 텍스트 한도는 얼마이고, 초과하면 어떻게 되나요?
- 셀 하나에 들어가는 텍스트는 5만 자가 한계입니다. 초과 시 저장이 조용히 잘리거나 실패해 그날 입력한 기록 전체가 유실될 수 있습니다.
- 사진이나 서명을 기록 행에 저장할 때 올바른 방법은 무엇인가요?
- data URL을 셀에 직접 넣지 말고, 파일을 Drive에 저장한 뒤 셀에는 fileId와 메타데이터만 남깁니다. data URL은 화면 export 전용 상태로만 사용합니다.
- 사용자 입력을 시트에 저장할 때 수식 주입을 막으려면 어떻게 하나요?
- =, +, -, @로 시작하는 값은 시트가 수식으로 해석하므로, 저장 전에 앞에 작은따옴표(')를 붙여 문자열로 처리합니다.
- 2026.07.29 Apps Script 프로젝트가 늘어나면 반드시 망가지는 것들
- 2026.07.16 매일 돌던 Apps Script 트리거가 갑자기 멈추는 이유
- 2026.07.15 브라우저 저장소에 고객정보 넣으면 생기는 문제
- 2026.07.07 브라우저가 내 데이터를 버릴 때: 초록 체크가 거짓말을 한다
- 2026.07.07 설치됨 ≠ 작동함: 백업 트리거가 한 번도 안 돌았다
- 2026.07.07 GAS엔 점진 배포가 없다: '맞는' 검사 하나가 전 사용자를 잠근다
- 2026.07.07 시트가 텍스트를 날짜로 바꾼다: '2026-06'이 완료를 영영 막을 때
- 2026.06.18 여러 사람이 한 시트에 쓰는 점검 앱: 동시성·중복·내보내기 설계
- 2026.06.12 셀을 한 칸씩 읽지 마라: 서비스 호출이 진짜 비용이다
- 2026.06.11 시트 셀에 JSON·이미지를 통째로 넣으면 터진다 지금 보는 글
- 2026.06.10 웹앱 배포 설정 하나가 보안 모델을 정한다: Execute as / 접근 권한
- 2026.06.09 GAS 6분 실행 한도: 멈추기 전에 끊어서 재개하라
- 2026.06.08 PropertiesService는 데이터베이스가 아니다: 9KB의 벽
- 2026.06.07 모바일에서 화면을 이미지로 저장할 때 멈추는 진짜 이유
- 2026.06.06 동시에 같은 시트를 쓰면 깨진다: LockService와 30 동시 실행 천장
- 2026.06.05 재배포할 때마다 주소가 바뀌면 안 된다: /exec URL 고정
- 2026.06.04 외부 호출은 가끔 실패한다: 지수 백오프와 재시도 예산
- 2026.06.03 HtmlService 앱은 껍데기 먼저: 비동기 로드와 모바일 뒤로가기
- 2026.06.02 GAS를 졸업해야 할 때: 한계 신호와 외부 DB 이전
- 2026.06.01 GAS에 지능과 엔진룸을 더하기: Vertex AI와 Cloud Run