什麼是 Hasura Migration?為什麼要用?

Published July 21, 2025 by 徐培鈞
資料庫

在多人協作的專案中,「環境不同步」幾乎是最常見、也是最致命的問題之一。

想像我們正在開發一個新功能,同事在本地的資料庫裡新增了一個 status 欄位,用來記錄訂單狀態。

這個改動在他的電腦上運作得非常正常,他寫好的程式碼也順利提交到 Git。

但問題發生在下一步——其他人拉下最新程式碼後,直接執行時卻報錯:「status 欄位不存在」。原因很簡單:

  • 我們本地的資料庫結構和他不一樣,根本沒有這個欄位。
  • 測試環境和 Production 也沒有同步更新。

結果是,這段新功能在正式環境一上線就爆炸了,所有呼叫到 status 欄位的 API 全部失敗,前端頁面也因此無法正常顯示訂單資訊。

為了緊急止血,我們直接登入 Production,手動加了一個 status 欄位。

但因為不確定同事最初的設計,我們選擇了錯誤的欄位型態與約束,導致幾天後資料開始異常。

最後,我們花了整整一天,才靠手動比對結構與修補資料把系統救回來。

這次經驗讓我們深刻意識到:資料庫結構和設定,不能只靠「口頭溝通」或「手動操作」來同步

只要有一個人忘了告訴其他人改了什麼,或某個環境更新慢一步,就可能引發災難。

這也是為什麼在專案開發中,Migration 是不可或缺的——它就像程式碼的版本控制一樣,讓資料庫的每一次變更都被完整記錄、可追蹤、可回滾,並且能輕鬆同步到任何環境。

Migration 的核心概念

什麼是 Migration?為什麼要叫「版本檔案」?

在開發專案時,程式碼會用 Git 進行版本控制,因為每一次修改都需要被追蹤、能回溯、能還原

Migration 的概念其實一模一樣,只不過它追蹤的不是程式碼,而是資料庫或系統設定的變更

你可以把 Migration 想像成「資料庫的 Git Commit」:

  • 每一次資料庫的結構更新(例如新增欄位、修改欄位型態)都會被保存成一個可以被版本控制的檔案
  • 這些檔案通常會被放進 Git,一起跟著程式碼版本走,確保所有人、所有環境的資料庫結構都是同步的。

Up / Down:讓每一次改動都能「進也行、退也行」

為什麼資料庫改動需要這麼謹慎?

在開發一個系統時,資料庫的結構不是一成不變的。

隨著功能更新,我們常常要:

  • 新增欄位(例如多出「訂單狀態」「使用者角色」)
  • 修改欄位型態(例如原本是 INT,後來改成 VARCHAR
  • 刪除不用的表或欄位(例如舊版功能下線後的殘留欄位)

這些動作看似普通,但它們都是「不可逆」的風險操作

假設今天你直接在 Production 上手動加了一個欄位,過幾天發現這個欄位多餘了,你要怎麼還原?

如果在手動刪除時不小心動到別的欄位,甚至可能造成資料錯誤或遺失。

更麻煩的是,如果這些改動沒有被「記錄」和「共享」,每個人環境都可能不一樣:

  • 你的本地有 status 欄位,但同事的本地沒有
  • 測試環境的資料表和 Production 不一致
    這就是所謂的「環境不同步」,在多人協作時會引發嚴重問題。

Migration 的解法:把每次改動都做成「可前進、可退回」的版本

為了避免這種混亂,Migration 引入了一個簡單卻強大的規則:

每一次資料庫的改動,都必須成對記錄「要怎麼前進」以及「要怎麼退回」。

這兩個步驟被稱為:

  1. Up(升級):往前走,讓資料庫升級到新版本
  2. Down(回滾):退回去,讓資料庫回到改動前的版本

這就像給資料庫裝上一個「時光機」——你可以放心地嘗試新改動,因為你知道隨時可以回到安全狀態。

Up(升級):告訴資料庫「我要怎麼升級到新版本」

在 Migration 裡,Up 腳本就是負責「升級」的操作,你可以把它想像成一份「更新說明書」。

每次執行 Up,就好像告訴資料庫:「請按照我寫好的步驟,把自己更新成最新的結構。」

Up 腳本可以包含很多種改動,例如新增欄位建立新表加索引修改欄位型態等等。

所有讓資料庫「往前走」的動作,都會被寫在 Up 裡。

✅ 例子:新增一個欄位

假設現在有一個 orders 資料表,原本只記錄「訂單金額」與「商品名稱」。

某天產品經理說:「我們需要知道每個訂單的狀態(例如 pending、paid、canceled)。」

這代表你必須在資料庫裡加一個欄位來記錄這個狀態。

在 Migration 的做法是,你會在 Up 腳本裡寫下這樣一段 SQL:

ALTER TABLE orders ADD COLUMN status VARCHAR(20) NOT NULL DEFAULT 'pending';

當你執行 Migration 時,系統就會根據這段指令幫你升級資料庫結構,讓 orders 表多出一個 status 欄位。

✅ SQL 的逐行解析

為了讓新手完全理解,這段 SQL 我們逐行拆開講:

  1. ALTER TABLE orders
  • ALTER TABLE:表示我要「修改」一張已經存在的表
  • orders:目標是 orders 這張訂單表
  1. ADD COLUMN status
  • ADD COLUMN:新增一個欄位
  • status:這個新欄位的名稱
  1. VARCHAR(20)
  • 表示這個欄位是「文字型態」
  • 20 的意思是最多可以輸入 20 個字元(例如 pending、completed 都在這個範圍內)
  1. NOT NULL DEFAULT 'pending'
  • NOT NULL:這個欄位不能留空
  • DEFAULT ‘pending’:如果沒有特別指定值,會自動帶入 pending(例如舊有訂單的狀態會自動補成 pending)

✅ 執行 Up 腳本後會發生什麼?

當你執行這個 Up 腳本後:

  • 資料庫的結構會立即更新,orders 表裡出現了一個名為 status 的新欄位
  • 所有新建立的訂單都會有 status 欄位,預設值是 pending
  • 舊有訂單的這個欄位,也會自動被補上 pending

從這一刻起,程式可以開始安全地讀取和寫入這個欄位。

Down(回滾):告訴資料庫「如果錯了,怎麼退回去」

資料庫的改動並不是一成不變的,需求隨時可能變、錯誤隨時可能發生

舉幾個真實情況:

  • 你加的 status 欄位後來被發現型態設計錯了,其實應該用 ENUM 而不是 VARCHAR
  • 產品經理改了需求,這個欄位短期內不需要,甚至可能被刪除
  • 新功能上線後造成了 API 錯誤,必須緊急回到上個穩定版本

在這些情況下,如果你只靠手動執行 SQL 去修補,就會遇到兩個大問題:

  1. 風險高:手動刪或改 SQL,很容易因為一個拼錯或順序錯誤而導致更嚴重的問題
  2. 難維護:每次都要重新思考「上次怎麼改的?怎麼還原?」根本無法保證一致性

這就是 Down 腳本存在的意義——它就像一顆「後悔藥」,專門用來撤銷 Up 的操作,把資料庫完整地退回到改動前的狀態

✅ 例子:刪掉剛新增的欄位

接續前面 Up 的例子,我們在 orders 資料表加了一個 status 欄位。

如果現在需要撤銷這次改動,Down 腳本就是這麼簡單直接:

ALTER TABLE orders DROP COLUMN status;

這段 SQL 的意思是:

  • ALTER TABLE orders:我要修改 orders 這張表
  • DROP COLUMN status:刪掉 status 這個欄位

當你執行 Down 腳本後,資料庫會回到執行這次 Up 之前的狀態,也就是 「好像這個欄位從沒被加過」

Up / Down 帶來的三大好處

Migration 之所以重要,核心原因就是它讓資料庫的變更「有跡可循、可控可退」

如果沒有 Up / Down,資料庫就像一條單行道:你改動過一次,就很難回頭,萬一出錯,只能手動補救。

而 Up / Down 則讓資料庫變成一條「可以隨時掉頭的雙向車道」。

以下是 Up / Down 帶來的三大實際好處,每一個都能解決真實開發中的痛點。

可進可退,讓改動更有安全感

✅ 問題:一次改錯,後果可能很嚴重

在沒有 Migration 的環境下,一旦資料庫結構改錯,後果可能是災難性的:

  • 你直接在 Production 新增了一個欄位,後來發現型態設計錯誤
  • 或者你刪錯了表,導致部分功能掛掉,甚至資料無法還原

很多時候,你只能臨時手動補 SQL 嘗試「修回來」,但這種補救不僅複雜,而且非常容易引發連鎖錯誤。

✅ 解決:Up + Down 的安全網

有了 Up / Down,每一次改動都可以隨時退回

  • Up 幫你安全地一步步升級
  • Down 幫你在幾秒內回到改動前的安全狀態

這就好像你在做實驗時,桌上隨時放著一個「撤銷鍵」,讓你敢於嘗試而不怕犯錯。

✅ 真實場景舉例

一個團隊在 Production 上新增了一個 status 欄位,結果 API 呼叫報錯。

如果沒有 Down,他們可能要熬夜比對資料、手動修復;

有了 Down,只需執行一條指令,幾秒鐘內就回到穩定版本,系統立刻恢復。

多人協作不再混亂

✅ 問題:不同環境不同步是災難的開始

多人協作時,最常見的問題就是「環境不同步」:

  • A 同事的資料庫有新欄位,但 B 同事沒有
  • Staging 和 Production 的表結構不同,導致部署時 API 報錯

這些問題往往因為「沒有一致的改動記錄」而發生——大家都各自用手動 SQL 修改,誰也不知道對方到底改了什麼。

✅ 解決:統一的 Up / Down 流程

Migration 強制每一次改動都要被寫成 Up / Down 檔案並放進版本控制中:

  • 所有人都執行同一套 Up 腳本 → 每個環境的資料庫結構一定一致
  • 如果需要回滾,所有人也可以用相同的 Down → 確保各環境同步退回相同版本

✅ 真實場景舉例

以前,一個新欄位加上去後,常常有人忘了告訴其他同事,結果部署時直接報錯。

用了 Migration 之後,只要同事拉取最新程式碼並執行 Up,資料庫結構就會自動更新一致,不需要再額外提醒。

部署更可控,降低上線風險

✅ 問題:部署失敗可能導致服務掛掉

在傳統做法中,資料庫變更通常直接在 Production 執行,過程中有很多不確定性:

  • SQL 寫錯可能導致資料錯亂
  • 執行順序錯誤可能導致部分表結構更新一半就停住
  • 緊急修復需要臨時補 SQL,非常危險

✅ 解決:可預測的升級與回滾流程

有了 Up / Down,你可以把部署流程變得可控且可驗證:

  1. 上線前先模擬
    在測試環境中,先跑一次完整的「Up → Down → 再 Up」循環,確認升級和回滾都不會出錯。
  2. 上線時更安心
    正式部署時,如果中途遇到錯誤,只要執行 Down,立即回到舊版本,服務不中斷。

✅ 真實場景舉例

一個團隊在預發布環境測試時,發現 Up 腳本會在某個資料表卡住。如果這是在 Production 才發現,後果不堪設想;

因為事先演練了 Up / Down,他們及時修正了腳本,正式上線時一切順利。

小結:一個更容易理解的比喻

如果還是覺得抽象,你可以把 Up / Down 想像成「手機 App 更新」:

  • Up 就是你安裝 App 新版本,獲得新功能;
  • Down 就是當你發現新版本有 Bug 時,一鍵退回上一個穩定版本。

Migration 幫資料庫實現的,就是這種「隨時可進可退」的能力。

一句話總結:

Up 讓資料庫往前,Down 讓資料庫退回。Migration 就是給資料庫加了一個版本控制系統,讓每次改動都有跡可循、可同步、可回退,避免任何一次改動變成無法挽回的災難。

Hasura 是什麼?為什麼它這麼特別?

在理解了 Migration 的重要性之後,你可能會好奇:

「那 Hasura 又是什麼?它和 Migration 有什麼關係?」

簡單來說,Hasura 是一個幫你快速生成 GraphQL API 的平台

它的最大特點是:

  • 你只要準備好資料庫,Hasura 就能自動幫你把資料庫轉換成一個可用的 API
  • 不用手寫一大堆後端程式碼,也能立即透過 GraphQL 查詢、修改資料

為什麼需要 Hasura?(它解決了什麼問題)

在傳統開發中,如果你要讓前端可以讀取資料庫裡的資料,通常需要:

  1. 自己寫後端程式(例如用 Node.js、Django)
  2. 設計 API(定義 GET/POST 路由)
  3. 寫一堆 SQL 或 ORM 查詢
    這個過程至少要花好幾天,甚至幾週。

Hasura 幫你省去了這些繁瑣的步驟:

  • 你只要把資料庫接上去,它就能立刻幫你生成 GraphQL API
  • 前端直接透過 GraphQL 就能查詢資料,對後端開發經驗不足的團隊來說,開發速度能快幾倍

Hasura 的核心功能

Hasura 不只是「把資料庫變成 API」那麼簡單,它還有很多實用功能,幫助你快速構建一個完整的後端服務:

即時生成 GraphQL API

  • 資料庫新增一個表或欄位,API 會自動更新
  • 不需要重新部署或手寫程式碼

權限與角色管理

  • 你可以直接在 Hasura 後台設定:哪些使用者能查詢哪些資料
  • 例如「一般使用者只能查自己的訂單,管理員可以查所有訂單」

資料表關聯自動識別

  • 如果兩個表之間有外鍵關聯,Hasura 會自動生成「關聯查詢」
  • 例如你可以直接用 GraphQL 查「訂單 + 該訂單的用戶資料」

支援事件觸發器與遠端 Schema

  • 當資料庫發生特定變化時(例如新增一筆訂單),Hasura 可以觸發 Webhook
  • 還能把其他服務的 GraphQL Schema 合併進來

為什麼 Hasura 也需要 Migration?

Hasura 的強大之處在於,它能自動幫你把資料庫變成 GraphQL API,讓開發速度大幅提升。但這個「強大」也帶來了一個很現實的挑戰:

Hasura 的 API 是直接依賴資料庫結構的。

換句話說,只要資料庫結構有變動,Hasura 生成的 API 也會跟著改變。

資料庫結構不同步,API 立刻報錯

在 Hasura 中,資料庫和 API 是緊密綁定的:

  • 當你新增一個欄位,Hasura 會自動生成查詢與修改這個欄位的 API
  • 當你刪除或修改一個欄位,對應的 API 也會隨之變更,甚至直接消失

這也意味著:

只要不同環境的資料庫結構不同步,API 就一定不同步。

舉個例子:

  • 在本地新增了一個 status 欄位,Hasura 生成了 status 相關的 GraphQL API
  • 但 Production 沒有這個欄位,API 卻依然被前端呼叫
  • 結果正式環境立刻報錯:「欄位不存在」

這種錯誤在 Hasura 專案裡非常常見,因為它不像傳統後端有「中間層」緩衝,一切都直接跟著資料庫跑。

Metadata 也需要同步,否則行為不一致

Hasura 不只是單純把資料庫映射成 API,它還有許多自己的「設定」會影響 API 的行為,這些設定被稱為 Metadata,包括:

  • 權限設定:不同角色能不能查詢或修改某些欄位
  • 表之間的關聯:Hasura 如何判斷 ordersusers 的關係
  • 事件觸發器:例如「當新增一筆訂單時,自動觸發一個 Webhook」

如果這些 Metadata 沒有在各環境之間同步,就會出現非常棘手的問題:

  • 你在本地加了「只有管理員可以刪除訂單」的權限,但 Production 沒有更新,結果所有人都能刪除
  • 你在 Staging 設了表關聯,前端可以查「訂單+用戶」的聯表資料,但 Production 上查不到
  • 你在測試環境用事件觸發器成功發送通知,但正式環境卻沒有執行

這些錯誤往往比資料庫結構不同步更難排查,因為它們不會直接報錯,而是「在不同環境表現不一致」。

為什麼一定要用 Migration?

以上問題都有一個共同點:

「不同環境沒有保持同步」

在 Hasura 專案裡,Migration 的角色就是:

  1. 追蹤所有資料庫結構變更(Database Migration)
  2. 追蹤所有 Metadata 設定變更(Metadata Migration)

只有這樣,才能確保:

  • 每個環境(本地、Staging、Production)資料庫結構完全一致
  • 每個環境的 API 行為完全一致
  • 發現錯誤時,可以用 Down 迅速回滾到安全狀態

簡單來說:

傳統 Migration 只是「資料庫的版本控制」,但在 Hasura 中,Migration 同時是「資料庫版本控制」+「API 行為版本控制」。

你說得對,我剛剛的《Hasura 與傳統 ORM 的不同》看起來雖然有表格,但核心只講到兩個面向:

  1. 追蹤範圍不同(Schema vs Schema + Metadata)
  2. API 行為依賴程度不同(Hasura 更敏感)

這樣確實不夠完整,對於「初學者要快速建立清晰全貌」來說太單薄。

Hasura 與傳統 ORM 的不同

很多人第一次接觸 Hasura Migration 都會問:

「我用過傳統 ORM 的 Migration,不就是追蹤資料庫結構嗎?Hasura 為什麼要搞得這麼複雜?」

原因在於:

Hasura 不只是管理資料庫結構,它還必須確保 API 行為在不同環境中完全一致。

以下從四個面向,帶你看出它與傳統 ORM 的明顯差異。

追蹤範圍不同:Hasura 要同步「兩層東西」

✅ 傳統 ORM

在傳統 ORM(例如 Sequelize、TypeORM)中,Migration 的工作很單純:

只追蹤資料庫結構(Schema)的變化

  • 例如「新增欄位」「修改欄位型態」「建立索引」
  • 重點是讓每個環境的資料庫「長得一樣」
    至於這些結構改動後,後端 API 要不要用、要怎麼用,是另一個獨立問題。

✅ Hasura

Hasura 不只要關心資料庫,還要關心自己「怎麼使用這個資料庫」。

因此它的 Migration 不只追蹤 Database Schema,還必須追蹤一個額外層級——Metadata,也就是 Hasura 的「行為邏輯」,包括:

  • 權限設定:哪個角色能查詢、修改哪些資料
  • 表關聯:Hasura 如何連接 ordersusers
  • 事件觸發器:例如「新增訂單時,是否觸發 Webhook」
  • 遠端 Schema / Actions:Hasura 是否串接其他外部 API

換句話說:

傳統 ORM 只在乎「資料庫該怎麼長」,Hasura 還要在乎「API 該怎麼行為」。

對 API 的影響程度不同:Hasura 更敏感

✅ 傳統 ORM

在傳統 ORM 的架構下,API 行為是由後端程式碼控制的。

就算資料庫多了一個欄位,如果後端沒寫對應邏輯,API 也不會受影響。

例如:

  • 你在資料庫加了一個 status 欄位,但後端程式沒有處理這個欄位 → 前端根本看不到它,也不會報錯。

✅ Hasura

Hasura 的 API 直接依賴資料庫結構與 Metadata 自動生成

  • 新增欄位 → API 立刻多一個查詢/修改這個欄位的能力
  • 刪除或修改欄位 → API 也會立即變動,甚至直接報錯

所以,只要資料庫或 Metadata 不同步,不同環境的 API 行為就可能完全不同

真實例子

  • 本地新增了 status 欄位 → Hasura 生成可查詢 status 的 API
  • Production 沒這個欄位 → 前端呼叫相同 API 時直接報錯「欄位不存在」

對多人協作與環境同步的要求更高

✅ 傳統 ORM

多人協作時,如果資料庫結構不同步,通常影響是:

  • 有些查詢可能拿不到資料,或回傳錯誤
  • 但 API 行為本身(由後端控制)大多不會直接掛掉

✅ Hasura

在 Hasura 中,任何不同步都可能直接影響 API 行為,甚至導致系統無法使用。
因為 Hasura 自動生成 API,它沒有「後端程式」作為緩衝。

真實例子

  • 權限不同步:本地設了「只有管理員能刪除訂單」,但 Production 沒更新 → 所有人都能誤刪訂單
  • 表關聯不同步:測試環境已設定 ordersusers 的關聯,前端能查「訂單+用戶」;但 Production 沒同步 → 聯表查詢直接報錯

因此在 Hasura 專案裡,Migration 幾乎是唯一能保證「資料庫結構+API 行為」一致的手段

回滾的重要性更高

✅ 傳統 ORM

回滾主要是針對「資料結構錯誤」:

  • 例如欄位型態不對、索引建錯
  • 回滾只是為了避免資料異常

✅ Hasura

Hasura 的回滾更關鍵,因為它同時影響 API 行為

  • Metadata 設錯權限 → 可能導致敏感資料外洩;Down 能立即撤銷,恢復安全設定
  • Production API 錯誤 → Down 能迅速退回上個穩定版本,讓服務立刻恢復

對高敏感度系統(例如金流、會員系統)來說,這種「秒級回滾」尤其重要。

總結:一張表看懂差異

傳統 ORM只追蹤資料庫結構(Schema)
Hasura追蹤資料庫結構 + Hasura 的 Metadata(權限、關聯、事件)
傳統 ORMAPI 與資料庫結構相對獨立
HasuraAPI 完全依賴資料庫與 Metadata,不同步直接報錯
傳統 ORM結構不同步 → 可能資料異常,但 API 不一定壞
Hasura結構/Metadata 不同步 → API 可能直接無法使用或行為錯誤
傳統 ORM避免結構錯誤
Hasura避免結構錯誤 + 緊急恢復 API 行為

Hasura Migration 怎麼運作?

要讓不同環境的資料庫結構與 Hasura 設定保持同步,Migration 在 Hasura 中扮演了關鍵角色。

它的運作邏輯很簡單:每次的變更都會被保存成一組檔案 → 這些檔案能被任何環境執行 → 確保資料庫與 API 行為一致

檔案結構概覽:Migration 的「存檔點」

Hasura 會把每一次的變更,都「存檔」到專案的特定資料夾中,就像遊戲存檔一樣,隨時可以回到某個狀態。
在 Hasura 專案裡,最重要的就是這兩個資料夾:

migrations/
  └── 1721456789012_add_user_table/
      ├── up.sql        # 升級腳本:告訴資料庫怎麼更新到新版本
      └── down.sql      # 回滾腳本:出錯時怎麼回到舊版本

metadata/
  ├── databases         # 每個資料庫的基本設定(連線、追蹤哪些表)
  ├── actions.graphql   # 自訂的 GraphQL Actions(例如呼叫外部 API)
  └── tables.yaml       # 資料表的權限、關聯、事件觸發器等設定

接下來,我們分別看看這兩個資料夾裡到底在幹什麼。

migrations/ 資料夾:資料庫結構的「時間機器」

✅ 它是什麼?

migrations/追蹤資料庫結構變更的地方,也就是 Database Migration 的核心。

每當你對資料庫做了結構上的改動(例如新增表、修改欄位、建立索引),Hasura 就會自動幫你「存一個檔」。

✅ 為什麼檔名會有時間戳?

Hasura 會用「時間戳 + 說明文字」來命名每次的改動,例如:

1721456789012_add_user_table

這樣可以保證每次 Migration 的執行順序正確,也方便你快速知道這次改動做了什麼。

up.sqldown.sql 有什麼用?

up.sql(升級腳本)

告訴資料庫「要怎麼從舊版本升級到新版本」。

例如新增 users 表的 SQL:

CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  name TEXT NOT NULL
);

down.sql(回滾腳本)

如果升級後發現錯誤,可以用它退回舊版本。
對應的 SQL 可能是刪掉 users 表:

DROP TABLE users;

✅ 實際用途

這個資料夾就像「資料庫的時間機器」:

  • 在本地開發時,確保每個人都能跑相同的 up.sql,得到一致的資料庫結構
  • 在正式環境出錯時,直接執行 down.sql,就能快速回到穩定狀態

metadata/ 資料夾:Hasura 行為的「控制面板」

✅ 它是什麼?

metadata/ 是 Hasura 特有的部分,專門存放 Hasura 自己的設定(也就是 Metadata Migration)。

這些設定會直接影響 API 的行為,如果不同步,很可能導致 API 出錯或行為不一致。

✅ 裡面都放什麼?

  • databases/:每個資料庫的基本設定,例如連線資訊、哪些表被 Hasura 追蹤
  • tables.yaml:記錄每張表的詳細設定,包括:
  • 哪個角色能查詢/修改這張表(權限)
  • 這張表和其他表的關聯(關聯查詢)
  • 是否綁定事件觸發器(例如新增資料後自動觸發 Webhook)
  • actions.graphql:如果你有自訂 GraphQL Actions(例如串接外部 API),這裡會記錄相關設定

✅ 為什麼重要?

想像兩個環境:

  • 本地:你設定了「只有管理員能刪除訂單」
  • Production:忘了同步,結果「所有人都能刪除訂單」

這種問題往往比結構錯誤更嚴重,而 metadata/ 就是防止這種災難的唯一保險。

一句話總結

  • migrations/:記錄資料庫「長什麼樣」,確保結構在各環境一致
  • metadata/:記錄 Hasura「怎麼使用資料庫」,確保 API 行為在各環境一致

你可以把它們想成:

migrations/ 是「骨架」,metadata/ 是「神經系統」。缺一不可,否則整個系統會「身體健全但行為錯亂」。

Migration 的生命週期:從「產生」到「同步」

Hasura 的 Migration 就像公司在更新一份正式作業流程(SOP),你不只是要把新流程擬好,還要確保能執行、所有部門同步,並定期檢查每個部門是不是按最新流程在做事

整個過程可以分成四個步驟:「擬流程 → 試行 → 正式上線 → 稽核確認」

產生(generate)— 擬定新流程並記錄下來

當你在 Hasura Console 做了改動(例如新增 users 表),這就像你決定要更新一份公司 SOP。

你必須把這個「新流程」正式記錄下來,否則其他同事根本不知道你改了什麼。

執行指令:

hasura migrate create "add_user_table" --from-server

✅ Hasura 幫你做了什麼?

  1. 比對差異:Hasura 會自動檢查「新流程和舊流程」有什麼不同
  2. 建立新檔案夾:以「時間戳 + 說明」命名,例如:
    1721456789012_add_user_table(方便知道「什麼時候」加了「什麼」)
  3. 寫入兩種腳本
  • up.sql(新流程怎麼做):例如「新增一個 users 表」
  • down.sql(怎麼退回舊流程):例如「刪除這個 users 表」

✅ 職場情境類比

這就像你寫了一份新的「報銷流程文件」:

  • up.sql = 新的報銷規則
  • down.sql = 萬一效果不好,要怎麼退回舊規則
    這一步是「寫下正式文件」,而不是靠口頭傳話。

驗證(CI)— 小範圍試行,確認流程沒問題

新流程擬好後,不能直接推給全公司,你需要先「內部試行」,確保新 SOP 沒有明顯錯誤。

在 CI/CD 流程裡,Hasura 會自動幫你檢查:

  • Up 腳本能否順利執行?(新流程能不能正常跑起來)
  • Down 腳本能否成功回滾?(萬一出問題,能不能退回舊版本)
  • 能否重複「執行 → 回滾 → 再執行」?(確保流程穩定、可重複)

✅ 職場情境類比

就像你先在一個部門試跑新的報銷流程:

  • 員工照新 SOP 報銷,看是否能順利完成(Up)
  • 如果流程太複雜或造成錯誤,就馬上退回舊流程(Down)

這一步是「試水溫」,避免把有問題的 SOP 推給所有部門。

套用(apply)— 全公司正式上線新流程

確認沒問題後,就可以把這份新 SOP 正式發佈到所有部門(對應 Staging 或 Production 環境)。

執行指令:

hasura migrate apply --endpoint=$STAGING_URL

✅ Hasura 幫你做了什麼?

  1. 依序執行所有未跑過的 Up 腳本
  2. 更新資料庫結構,讓每個環境都用相同「新 SOP」
  3. 同步 Metadata 設定,確保 Hasura 的 API 行為也一致(誰能操作什麼、表關聯、事件觸發器等)

✅ 職場情境類比

這就像你把新報銷 SOP 正式發給所有部門,大家從今天起都按這個新流程做事,避免有部門還在用舊規則。

版本對齊(status)— 定期稽核,確認每個部門都跟上

最後一步是「對帳與稽核」,你要定期檢查所有環境是不是在跑同樣的 SOP。

執行指令:

hasura migrate status

✅ Hasura 幫你檢查什麼?

  • 每個環境目前執行到哪個 Migration
  • 是否有版本不同步(例如 Production 落後一個版本)

✅ 職場情境類比

就像你定期請內控部門檢查:「每個部門是不是都用最新報銷 SOP?」
如果發現有人還在用舊規則,馬上補送文件,避免報銷出錯。

一句話小結

Hasura Migration 就是一套「職場 SOP 管理系統」: 擬流程(generate) → 試行驗證(CI) → 全公司上線(apply) → 定期稽核(status)。 這樣才能確保所有部門都照同樣的 SOP 做事,而且隨時能退回舊流程。

實務場景:如何判斷「要不要 Migration」?

很多初學者常問:

「我每次在 Hasura Console 點來點去都要寫 Migration 嗎?」

其實不用那麼死板,只要搞懂下面這個三步驟思考流程,你就能快速判斷。

思考流程:三種情況快速判斷

你可以用這個簡單邏輯問自己:

我現在在做什麼?

├── 改動 Schema(新增欄位 / 刪除欄位 / 修改型態 / 建立索引 / 新增 Table)
         需要 Database Migration

├── 改動 Hasura 設定(新增權限 / 修改角色 / 關聯設定 / Event Trigger)
         需要 Metadata Migration

└── 只是灌入資料(INSERT / UPDATE / DELETE)
          不需要 Migration

CI/CD 串接示例:實際在專案裡怎麼用?

在實際專案中,Migration 通常會配合 CI/CD 自動化流程,確保每次部署都執行最新的 Migration。

✅ 最簡單的 GitHub Actions 範例

- name: Apply Hasura Migration
  run: hasura migrate apply --endpoint=$PROD_URL

這行指令會在正式部署時:

  • 自動執行所有未跑過的 Up 腳本
  • 同步 metadata/ 設定,確保 API 行為一致

✅ 遇到錯誤怎麼辦?

Hasura 最大的好處之一就是可以「快速回滾」:

hasura migrate apply --down 1

這行指令會把最後一次 Migration 撤銷掉,就像把錯誤的 SOP 撤回,馬上回到上一個穩定版本。

初學者最常問的 4 個問題

只新增資料(INSERT)需要 Migration 嗎?

不需要。

Migration 追蹤的是結構與設定,而不是資料本身。

舉例

  • 你幫新用戶補一筆訂單(INSERT) → ❌ 不用
  • 你幫訂單表新增一個 status 欄位 → ✅ 要用 Migration

手動改 Production 資料庫可以嗎?

千萬不要!

手動改就像你私下改了 SOP 但沒告訴其他人,最後會導致:

  • 本地和正式環境不同步
  • API 報錯(例如本地有 status 欄位,Production 卻沒有)

正確做法:

一定要用 Migration 改動,這樣所有環境都能同步。

Migration 跟 Seeder 有什麼差別?

Migration = 結構/設定的版本控制
Seeder = 插入或初始化資料

舉例

  • Migration:新增 users
  • Seeder:新增一筆「admin」帳號到 users

兩者功能完全不同,Seeder 不能取代 Migration。

Hasura Cloud 的自動備份能取代 Migration 嗎?

不能。

  • 備份 = 災難復原(例如硬碟壞掉,用備份還原整個資料庫)
  • Migration = 版本控制(例如按時間順序一步步升級或回滾)

兩者用途不同,Migration 是日常必須使用的工具。

一句話小結

能改變「結構」或「設定」的,都應該寫進 Migration; 只處理「一次性資料」的,不需要。 Migration 是團隊協作下唯一能保證「環境同步+可回滾」的安全機制。

結語 & 下一步

一句話收斂:

Migration 是 Hasura 專案的保險絲,也是讓你回到過去的時間機器。

下一步建議

如果你已經理解什麼是 Migration,下一篇可以深入學習 《Hasura Migration 三種類型一次搞懂》,詳細拆解:

  • Database Migration
  • Metadata Migration
  • Data-only Migration(Seeder)