# 把 Vercel 部署儲存空間從 13.96 GB 降到 20.27 MB — 關閉預覽、縮短保留期

> Vercel Hobby 方案的部署儲存空間超過了 10 GB 上限。原因是由部署次數造成的：每次部署都會增加 147 MB，三十天內部署了 189 次。

- Source: https://oharu121.com/zh-tw/blog/vercel-hobby-deployment-storage-previews-retention-prune/
- Published: 2026-09-24T14:05:22+09:00
- Tags: Vercel, 開發工具, Claude Code

---
## 引言

Vercel 的用量頁面在 Deployment Storage 旁邊顯示了一個紅圈：免費額度 10 GB，用掉 13.96 GB。同一個帳戶裡，其他項目沒有一項超過上限的 20%。

*Image: 標題為「Exceeded free resources」的 Vercel 用量面板，Deployment Storage 為 10 GB 中的 13.96 GB 並標上紅圈，Functions Storage 為 10 GB 中的 2 GB，Edge Requests 為 1M 中的 45K，Speed Insights Events 為 10K 中的 267*

我第一個想知道的是線上網站會不會受影響。答案是不會。不過一直超過上限還是有代價的：Vercel 會不再遵守 30 天的保留期，會直接刪掉符合條件的部署，也有可能在回到額度以內之前拒絕新的部署。

我一開始懷疑的是 repo，畢竟這裡每篇文章都帶著圖表和截圖。然而 repo 打包後只有 9.79 MiB，所有影像和影片加起來也才 9.4 MB。**這個網站部署一次用掉的空間是 147 MB，而三十天內共部署了 189 次**。

關掉預覽建置、把保留期縮到一天，並且在發布流程的開頭加上清理處理，最後成功讓 Deployment Storage 變成了 **20.27 MB**。

## 讀懂配額：一次建置 147 MB，repo 9.79 MiB

Deployment Storage 量的是每次部署所保留的建置產物，在這個網站上**大約是 repo 本身的 15 倍大**。

兩個數字各用一行指令就能拿到。

```bash
git count-objects -vH | grep size-pack
# size-pack: 9.79 MiB
```

```bash
du -sm .vercel/output
# 147	.vercel/output
```

配額算的是後者。`.vercel/output` 是 `vercel build` 產生、`vercel deploy --prebuilt` 上傳的東西。部署端的檔案樹有 2847 個檔案，本機是 2843 個，傳輸過程中沒有多出什麼實質內容。

### 147 MB 分布在哪裡

**每次部署有一半是伺服器 bundle，而這一半裡面有 20 MB 是它自己的第二份複本**。

*Figure — BuildBreakdown: 這個網站一次建置的目錄組成。伺服器 bundle 出現了兩次，`static/_astro` 則是三種語系共 893 個影像衍生檔。*

`_render.func` 裡面有 29 MB 的 `node_modules`，也就是 Astro 的伺服器執行環境，加上文章頁在算繪時會引入的一切。`static/_astro` 是 Astro 寫出處理後影像的位置，**那 893 個檔案，是同一批原始圖片在三種語系下產生的衍生檔**。

### 把影像搬到外部為什麼只能省下 6%

這個 repo 裡所有影像和影片加起來是 9.4 MB，所以就算全部搬去物件儲存的 bucket，**能省下的空間也只有一次部署的十六分之一**。

```bash
find src -type f \( -name '*.mp4' -o -name '*.png' -o -name '*.jpg' -o -name '*.webp' -o -name '*.avif' \) -exec du -ch {} + | tail -1
# 9.4M	total
```

配額算的是 `static/_astro`，那些衍生檔是建置時從原始圖片產生的。把原圖改由 bucket 提供，只是把 9.4 MB 移出 git，33 MB 的衍生檔原封不動留在部署包裹裡。

**就算我能夠把 147 MB 砍成一半，佔用 Deployment Storage 的空間還是會隨著部署次數一路疊加上去**，因此管理單次部署的大小並非解決問題的關鍵。

## 三十天內 189 次部署

儲存空間等於建置大小乘以部署次數，而**我之前從來沒去關注過部署次數這一項**。

*Figure — QuotaArithmetic: 把配額填滿的乘積。看得見的槓桿是 147 MB，真正在起作用的是 189。*

GitHub 會為每次部署留下紀錄，所以次數是從 repo 而不是從 Vercel 取得的。

```bash
gh api "repos/<owner>/<repo>/deployments?per_page=100" --paginate
```

把最近三十天的紀錄依建立者分組，`vercel[bot]` 對 `Preview` 環境建立了 122 次，這個 repo 自己的 CI 對 `production` 建立了 67 次。

以每次 147 MB 計算，**189 次部署等於一個月內往 10 GB 的額度裡灌進 27.8 GB**。

### 沒人打開過的 122 個預覽

**這些部署有三分之二是早已合併並刪除的分支所留下的預覽**，而且每一個都是自動建立的。

留下來的四個部署，每一個都是某個分支的最新預覽。那些分支都已經在 squash 合併後被刪掉，`git ls-remote --heads origin` 一個也列不出來。

即使這些分支早已被刪除，**Vercel 仍然保留了這些分支的最新預覽，而並沒有察覺這些分支已經不存在了**。

## 關掉預覽、縮短保留期，再清理一次

三個設定，分別對著乘積裡的一項：部署被建立的頻率、被保留的時間，以及此刻還擺在那裡的數量。

### 關掉 Git 整合

Vercel 的 Git 整合預設會替每一次 push 都會建立一個部署，不分分支。因此每個部署都佔用 147 MB 的 Deployment Storage。

這個網站不需要那些自動部署：正式環境是由 GitHub Actions 部署的，其他分支的部署也都不需要。

```json title="vercel.json" ins={3}
{
  "git": {
    "deploymentEnabled": false
  }
}
```

這會停掉包含 main 以及所有其他分支的 Git 整合所自動產生的部署。

### 保留期是 Project Settings 裡的四個下拉選單

保留期設定在 Vercel 的控制台，位於 Project Settings 的 Build and Deployment 底下，名稱是 Deployment Retention Policy。這個帳戶裡的每個專案都停在方案的預設值。

| 部署類型 | 變更前 | 變更後 |
| --- | --- | --- |
| Canceled | 30 天 | 1 天 |
| Errored | 30 天 | 1 天 |
| Pre-Production | 30 天 | 1 天 |
| Production | 30 天 | 1 天 |

**30 天是 Hobby 方案的上限，所以預設值同時也是最慢的那個設定**。四項全部改成最短的值。

*Image: Vercel 的 Deployment Retention Policy 面板，Canceled Deployments、Errored Deployments、Pre-Production Deployments、Production Deployments 四個下拉選單都顯示「1 day」*

*負責預覽的是 `Pre-Production Deployments` 那一列。這裡沒有設定要保留幾個部署的欄位。*

> **小心喔**
>
> **保留期不是刪除佇列**。設定政策只是讓部署變成可刪除，並不會真的刪。在這個帳戶裡，185 個存活的部署中有 148 個早就超過 30 天的保留期，卻仍然沒有被刪除。

在 Hobby 方案上，`vercel usage` 什麼都報不出來。

```bash
pnpm dlx vercel@58 usage
# Error: Billing cost data is unavailable for 2026-09-01 through 2026-09-21.
```

Hobby 方案沒有帳務紀錄，CLI 也就無從讀起。GB 這個數字只存在於控制台。

### `--safe` 保住什麼，又刪掉什麼

這裡我們使用 `vercel remove <project> --safe`，會指定 `--safe` 是因為如果不加的話會刪掉整個專案。

```bash
pnpm dlx vercel@58 remove oharu-tech-blog --safe --yes
# > Found 8 deployments for removal in oharu121s-projects [1s]
# > Success! Removed 8 deployments [909ms]
```

然而 `--safe` 會跳過持有別名的部署，因此有四個持有分支別名的預覽也一起被留了下來。

*Figure — TwoPassPrune: `--safe` 刪掉的八個，和它放過的四個。預覽的分支別名活得比它指向的分支還久，所以第二次要逐一指名部署。*

十三個部署刪掉八個，剩下五個：線上那個正式部署，加上四個分支早就沒了的預覽。確認過分支真的不在之後，這四個只能用 URL 逐一指名刪除。

```bash
pnpm dlx vercel@58 remove <url> <url> <url> <url> --yes
# > Found 4 deployments for removal in oharu121s-projects [934ms]
# > Success! Removed 4 deployments [731ms]
```

> **挖哩咧**
>
> **指定專案名並拿掉 `--safe` 會刪除整個專案**。第二條指令沒有 `--safe`，而 `vercel remove` 收到專案名稱又少了這個旗標時，會連同網域、環境變數和所有已儲存的密鑰一起刪掉。這裡必須指定部署的 URL。

## 清理該放在發布流程的哪裡

清理要放在發布流程的開頭。放在結尾的話，正式環境才剛換上新版本，舊的那個部署就被刪掉了，想回滾也沒得回。

*Figure — PrunePlacement: 在部署前清理，前一次的正式部署會在最可能需要回滾的那段區間裡一直存在。在部署後清理，它正好在那個時候被刪掉。*

## 從 13.96 GB 到 20.27 MB

*Image: Vercel Deployment Storage 三十天總量的折線圖，從不到 7 GB 開始，在 9 月 8 日前後升到接近 17 GB，到 9 月 21 日回落至 14 GB，接著在 9 月 22 日垂直掉到總計 20.27 MB*

*右側那道垂直的下墜就是清理。在那之前的斜率，是三十天內累積的 189 次部署。*

我做了三件事讓 Deployment Storage 從 13.96 GB 降到了 20.27 MB：關掉 Git 整合的自動部署、把四種保留期都改成一天，再用 `vercel remove` 把堆積的部署清掉。

## 總結

部署儲存空間等於建置大小乘以部署次數，而**比較容易判斷錯的是次數**。這個帳戶有十個專案、185 個存活的部署、147 MB 的建置，而 repo 小到對總量沒有影響。

要分辨這是儲存空間的問題還是 repo 的問題，有三個檢查。`du -sm .vercel/output` 給出一次部署的大小，平台自己的部署紀錄給出次數，**兩者的乘積對上額度，就能決定應該要把部署變小，還是要減少部署次數**。

如果問題出在次數，我們能做三件事：關閉 Vercel 的自動部署： `git.deploymentEnabled: false`、縮短舊部署的保留時間，以及手動刪除已經不需要的舊部署： `vercel remove --safe`。**能立竿見影的方法只有最後一個**，而且我們應該把它放在整個發布流程的開頭，而不是結尾。

## 參考連結

- [Vercel: Deployment Storage（這個指標算什麼，以及保留的例外）](https://vercel.com/docs/deployment-storage)
- [Vercel: Optimize deployment storage](https://vercel.com/docs/deployment-storage/optimize)
- [Vercel: Git configuration（deploymentEnabled 的布林值與分支物件兩種寫法）](https://vercel.com/docs/project-configuration/git-configuration)
- [Vercel changelog: Hobby projects now retain fewer deployments to free up storage](https://vercel.com/changelog/hobby-projects-now-retain-fewer-deployments-to-free-up-storage)
