EmDash 核心遷移會更新 EmDash 自己的資料表以及內容資料表上的標準欄。它們不會建立、刪除或重新命名你的集合與欄位;內容模型變更請參見演進已部署網站。
執行階段遷移模式預設為 auto,因此現有部署在啟動時會繼續套用待處理的核心遷移。部署管理的遷移讓建置在新應用程式碼接收流量之前遷移其資料庫,然後讓執行階段驗證或信任該部署步驟。
核心遷移僅向前。它們的撰寫方式允許在確定已完成的陳述式之後重試命令,但中斷的遠端命令可能留下模糊結果。安全的做法是用 emdash migrate --status 檢查同一資料庫,而不是假定整次遷移已執行或完全未執行。
建置、遷移、部署、檢查
Astro 建置或同步會寫入 .emdash/migrations.json。此無密鑰清單記錄該建置使用的精確 EmDash 版本、有序遷移集、地區設定組態以及轉接器遷移執行器。
從產生該清單的相依性所在專案執行這些命令。先建置並檢查目標。
pnpm build
pnpm emdash migrate --status
確認報告的目標是預期資料庫後,啟動互動式遷移。在提示處再次核對目標後再確認。然後部署同一建置並檢查已部署的架構。
pnpm emdash migrate
pnpm wrangler deploy
pnpm emdash migrate --check
emdash migrate --status 報告已套用、待處理與未知遷移,且不變更資料庫。普通的 emdash migrate 命令顯示目標,並在套用待處理遷移前請求確認。
--check 從不套用遷移,並在已知遷移待處理或資料庫包含建置未知的遷移記錄時以非零退出。若要檢查同一遷移集且不要 check 的非零「需要工作」退出狀態,請使用 --status。CLI 參考 區分待處理、未知、確認、中斷與操作退出碼。
非互動套用與每次 --json 套用都需要 --expected-target-fingerprint;若解析的目標不相符,命令會失敗。在自動化部署作業中使用這些選項,不要用於上面的互動工作流程。
對儲存在其他位置的清單使用 --manifest path/to/migrations.json。對於本機調查,--from-config [--config astro.config.mjs] 會明確評估受信任的專案組態,而不執行 Astro 勾點或啟動伺服器。部署管線應使用建置清單。
明確選取資料庫
已設定的轉接器向清單貢獻無密鑰目標資訊。認證保留在環境變數中,僅由遷移命令讀取。
| Adapter | Manifest target | Default credential variable | Useful override |
|---|---|---|---|
| SQLite | Database path or file: URL | — | --database <path> |
| libSQL | Public URL | TURSO_AUTH_TOKEN | Configure migrationAuthTokenEnv |
| PostgreSQL | Connection variable name | DATABASE_URL | --database-url-env <name> |
| Cloudflare D1 | Wrangler binding name | CLOUDFLARE_API_TOKEN | --d1, --account-id, --wrangler-config, --wrangler-env |
| Hyperdrive | Primary binding and origin variable name | Binding-specific direct-origin variable | Configure migrationConnectionStringEnv |
相對 SQLite 路徑從專案根解析,而不是從已安裝的 EmDash 套件或 shell 的目前子目錄。PostgreSQL、libSQL 與 Hyperdrive 目標標籤會省略認證與 URL 參數。
遷移前佈建 D1
建立 D1 資料庫與遷移其架構是分開的操作。emdash migrate 從不建立缺失的資料庫。
-
佈建資料庫並記錄其正式環境 UUID。
pnpm wrangler d1 create my-site-production -
將該 UUID 新增到
wrangler.jsonc中預期的繫結與環境。 -
建置網站,使 D1 繫結記錄到
.emdash/migrations.json。 -
設定帳戶 ID 與具有 D1 Edit 權限的限定範圍 API 權杖。檢查所選目標,然後執行互動式遷移。僅當帳戶與資料庫符合預期正式環境資料庫時才確認提示。
export CLOUDFLARE_ACCOUNT_ID="..." export CLOUDFLARE_API_TOKEN="..." pnpm emdash migrate \ --status \ --wrangler-config wrangler.jsonc \ --wrangler-env production pnpm emdash migrate \ --wrangler-config wrangler.jsonc \ --wrangler-env production
你也可以改為提供 --account-id 與 --d1 <database-uuid-or-name>。名稱查詢必須解析為恰好一個資料庫。預覽 ID、預留位置 ID、衝突帳戶與模糊繫結會 fail closed。
在 CI 中設定 D1 遷移
EmDash 在套用遷移時會在 D1 資料庫中持有遷移鎖,包括 emdash migrate 與 auto 模式下的執行階段遷移。在鎖被持有時啟動的第二次執行最多等待 10 秒。若第一次執行在該時間內結束,第二次執行會成功且不套用任何內容;否則會失敗且不套用遷移。對每個帳戶與資料庫 UUID 一次只執行一個遷移作業,使第二個作業在 CI 佇列中等待而不是失敗。
在 CI 環境中設定以下密鑰與變數:
- 密鑰
CLOUDFLARE_API_TOKEN:具有 D1 Edit 權限的限定範圍權杖。 - 變數
CLOUDFLARE_ACCOUNT_ID:擁有該資料庫的 Cloudflare 帳戶 ID。 - 變數
D1_DATABASE_ID:正式環境 D1 資料庫 UUID。 - 變數
EMDASH_TARGET_FINGERPRINT:在本機核對帳戶與資料庫後由emdash migrate --status列印的指紋。
以下 GitHub Actions 工作流程使用這些值,並按兩個不可變 D1 識別碼設定並行群組。其套用步驟是非互動的,因此明確提供已核對的目標指紋。
name: Deploy
on:
workflow_dispatch:
concurrency:
group: emdash-migrations-${{ vars.CLOUDFLARE_ACCOUNT_ID }}-${{ vars.D1_DATABASE_ID }}
cancel-in-progress: false
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm build
- name: Inspect EmDash migration target
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
run: |
pnpm emdash migrate --status --json \
--account-id "${{ vars.CLOUDFLARE_ACCOUNT_ID }}" \
--d1 "${{ vars.D1_DATABASE_ID }}"
- name: Apply EmDash migrations
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
EMDASH_TARGET_FINGERPRINT: ${{ vars.EMDASH_TARGET_FINGERPRINT }}
run: |
pnpm emdash migrate \
--account-id "${{ vars.CLOUDFLARE_ACCOUNT_ID }}" \
--d1 "${{ vars.D1_DATABASE_ID }}" \
--expected-target-fingerprint "$EMDASH_TARGET_FINGERPRINT"
- run: pnpm wrangler deploy
- name: Check EmDash migrations
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
run: |
pnpm emdash migrate --check \
--account-id "${{ vars.CLOUDFLARE_ACCOUNT_ID }}" \
--d1 "${{ vars.D1_DATABASE_ID }}"
僅在本機核對已變更目標後才更新 EMDASH_TARGET_FINGERPRINT。指紋不含認證,但未檢查帳戶與資料庫就變更它會移除防止遷移錯誤資料庫的保護。
釋放卡住的遷移鎖
在釋放遷移鎖之前停止的 D1 遷移執行會使鎖保持持有。當 CI 作業在 emdash migrate 期間被取消、auto 模式下的 Worker 在執行階段遷移期間停止,或開發伺服器在套用遷移時被停止時會發生這種情況。因遷移錯誤而失敗的執行會釋放鎖。EmDash 不會釋放它未持有的鎖,因為持有者可能仍在套用遷移,或可能已在某次遷移中途停止。在鎖被釋放之前,網站無法套用其待處理遷移,且在 auto 模式下 EmDash 會初始化失敗。
鎖被持有超過一分鐘後,emdash migrate 與執行階段遷移會停止等待並報告以下錯誤:
The migration lock has been held since 2026-09-01T12:00:00.000Z (lock 1788264000000). A migration may still be running; if none is, check the database and release the lock: https://docs.emdashcms.com/deployment/core-migrations/#release-a-stuck-migration-lock
釋放遠端 D1 資料庫的鎖使用 emdash migrate,因此需要寫入 .emdash/migrations.json 的建置以及具有 D1 Edit 權限的 API 權杖,如遷移前佈建 D1所述。
-
確認沒有遷移作業、部署或其他
emdash migrate命令正在對該資料庫執行。 -
使用遷移所用的相同目標選項檢查鎖與遷移集。
pnpm emdash migrate --status報告以鎖及其 id 開頭。若已停止的執行正在套用遷移,那是第一個待處理遷移,且可能已部分套用。
Migration lock: held since 2026-09-01T12:00:00.000Z (id 1788264000000)auto模式下的 Worker 在套用遷移時也可能持有鎖。一分鐘或更久後再執行該命令,並在已知已套用遷移仍在變化時等待,而不是釋放鎖。 -
用該 id 釋放鎖。命令會要求你確認目標,且僅在鎖仍具有該 id 時釋放。在非互動 shell 中,新增帶有
--status列印的目標指紋的--expected-target-fingerprint。pnpm emdash migrate --release-lock 1788264000000 -
再次套用待處理遷移。
pnpm emdash migrate若在第一個待處理遷移中套用失敗,將該遷移視為中途留下,並遵循疑難排解中關於模糊 D1 寫入的項目。
emdash migrate 僅到達遠端 D1 資料庫。當鎖在開發伺服器的本機 D1 資料庫中被持有時,停止伺服器並用 Wrangler 清除鎖,將 DB 取代為繫結名稱,將數字取代為錯誤中的鎖 id。
pnpm wrangler d1 execute DB --local --command "UPDATE _emdash_migrations_lock SET is_locked = 0 WHERE is_locked = 1788264000000"
Hyperdrive 連線到來源
Hyperdrive 的遷移執行器會開啟到來源的直接 PostgreSQL 連線。它不會透過 Hyperdrive 傳送遷移流量,不使用選擇性的快取繫結,也不從 Worker 繼承私人網路可達性。
部署執行器必須能夠到達來源。當預設的繫結特定變數不合適時,在 hyperdrive() 上設定 migrationConnectionStringEnv,並將該變數僅提供給遷移作業。將執行階段 Hyperdrive 認證與直接來源部署認證分開。
逐步採用執行階段強制
以下 EmDash 整合組態在開發中保留自動遷移的同時啟用執行階段強制。
emdash({
database,
migrations: {
runtime: "check",
dev: "auto",
},
});
auto是向後相容的預設值。執行階段啟動會檢查並套用待處理遷移。check執行單向狀態查詢,並在已知遷移待處理時在提供請求前回傳 503。它在滾動部署期間容忍來自較新相容建置的記錄。manual不執行執行階段遷移或狀態查詢。僅在部署管線可靠地套用並檢查每個建置之後使用。
當同一產物透過多個環境提升時,EMDASH_MIGRATIONS_MODE 可以覆寫執行階段模式。設定與開發繞過路由遵守有效模式;它們不能在 check 或 manual 背後靜默遷移。
保守推出是:引入部署作業時用 auto,作業可靠後用 check,對每次部署強制外部檢查時用 manual。
滾動部署期間的相容性
核心遷移遵循 expand/deploy/contract 順序。部署可能暫時對擴充後的資料庫執行新舊應用隔離區,回填可能仍在進行。在每個已部署版本停止使用某架構之前,不要收縮該架構。
未知的已套用遷移記錄僅在此滾動部署方向上被執行階段 check 容忍。CLI 的精確檢查會報告它們,且 apply 拒絕變更,因為資料庫可能更新,或可能有分歧的遷移歷史。
回滾邊界
部署先前的應用產物不會逆轉核心遷移。在套用待處理遷移之前,進行可還原的資料庫備份,並記錄與之相符的應用產物。若先前的應用無法在已遷移架構上執行,請一起還原遷移前的資料庫與應用。不要從 _emdash_migrations 刪除列,也不要將遷移的內部 down() 函式作為操作回滾執行。
修復混合的 PostgreSQL 擁有權
當現有 PostgreSQL 網站用多個擁有者建立了 EmDash 物件,且後續遷移因 must be owner of table 等錯誤失敗時,使用此執行手冊。選擇主 EmDash 連線將繼續使用的規範角色。進行可還原的資料庫備份,並在變更擁有權之前停止應用流量與架構變更。
檢查作用中架構中的每個資料表:
SELECT
n.nspname AS schema_name,
c.relname AS table_name,
pg_get_userbyid(c.relowner) AS owner
FROM pg_class AS c
JOIN pg_namespace AS n ON n.oid = c.relnamespace
WHERE n.nspname = current_schema()
AND c.relkind IN ('r', 'p')
ORDER BY c.relname;
EmDash 物件包括 _emdash_* 與 _plugin_* 系統資料表、ec_* 集合資料表,以及無前置詞資料表如 content_taxonomies、media、options、revisions 與 taxonomies。在專用 EmDash 架構中,每個應用資料表都應有規範擁有者。
EmDash 還會建立媒體使用觸發器所用的 PostgreSQL 函式。檢查函式擁有權,並為修復命令保留每個函式的參數簽章:
SELECT
n.nspname AS schema_name,
p.proname AS function_name,
pg_get_function_identity_arguments(p.oid) AS arguments,
pg_get_userbyid(p.proowner) AS owner
FROM pg_proc AS p
JOIN pg_namespace AS n ON n.oid = p.pronamespace
WHERE n.nspname = current_schema()
ORDER BY p.proname, arguments;
用可以變更擁有權的超級使用者或提供者角色轉移每個不相符的物件。使用清單中的真實架構、物件、角色與函式簽章,而不是原樣複製範例名稱:
ALTER TABLE emdash.content_taxonomies OWNER TO emdash_app;
ALTER TABLE emdash.ec_posts OWNER TO emdash_app;
ALTER FUNCTION emdash.emdash_media_usage_capture_work() OWNER TO emdash_app;
變更資料表的擁有者也會涵蓋其附加的索引、條件約束與觸發器,但不包括獨立的觸發器函式。重複兩個清單查詢,直到每個 EmDash 資料表與函式都報告規範擁有者。然後以該角色連線,並在重新啟動流量之前驗證 current_database()、current_schema() 與遷移狀態。
非超級使用者要轉移擁有權,必須擁有或繼承該物件的擁有權,能夠對新擁有者 SET ROLE,且新擁有者必須對架構有 CREATE。託管 PostgreSQL 提供者可能要求其管理角色執行轉移。
疑難排解
- No migration manifest found. Build or sync the project first. Use
--manifestfor a non-standard artifact location or explicitly choose--from-configfor local investigation. - The artifact does not match project EmDash. Rebuild and deploy the application and manifest together. Run the project’s CLI instead of a global installation.
- The target is missing or ambiguous. Provision it first, then supply an explicit database path, connection-variable name, D1 selector, or selected Wrangler config and environment. EmDash does not guess from unrelated environment variables or bindings.
- The target fingerprint changed. Stop and review the displayed account, environment, database name, UUID, or path. Update the expected fingerprint only after confirming the intended target.
- Unknown migration records are present. Do not delete the records or rerun apply. Confirm that the application artifact is the intended version and investigate whether a newer or divergent build migrated the database.
- A D1 write outcome is ambiguous. Do not replay the migration command. Run
emdash migrate --statusagainst the same account and database UUID, inspect the result, and escalate if the migration stopped part-way through. - Datetime normalization requires manual review. A legacy datetime falls in a repeated or skipped daylight-saving hour in the site’s configured timezone. The error lists each affected content row or revision. Correct those values with an explicit UTC offset, then retry the migration. The migration preflight does not write any datetime until every stored value can be resolved.
- Hyperdrive cannot connect. Test reachability from the deployment runner to the PostgreSQL origin and verify the direct-origin variable. Worker-to-Hyperdrive connectivity does not prove the runner can reach the origin.