Le migrazioni core di EmDash aggiornano le tabelle proprie di EmDash e le colonne standard delle tabelle di contenuto. Non creano, rimuovono né rinominano le tue collezioni e i tuoi campi; per le modifiche al modello di contenuto consulta Evolvere lo schema di un sito distribuito.
La modalità di migrazione a runtime è auto per impostazione predefinita, quindi i deployment esistenti continuano ad applicare all’avvio le migrazioni core in sospeso. Le migrazioni gestite dal deployment permettono a una build di migrare il proprio database prima che il nuovo codice dell’applicazione riceva traffico, e poi al runtime di verificare quel passo del deployment o di fidarsi di esso.
Le migrazioni core procedono solo in avanti. Sono scritte in modo che un comando possa essere ritentato dopo istruzioni che sono sicuramente state completate, ma un comando remoto interrotto può lasciare un risultato ambiguo. La risposta sicura è ispezionare lo stesso database con emdash migrate --status, senza dare per scontato che sia stata eseguita l’intera migrazione oppure nessuna parte di essa.
Compilare, migrare, deployare, verificare
Una build o una sincronizzazione di Astro scrive .emdash/migrations.json. Questo manifest, privo di segreti, registra l’esatta versione di EmDash, l’insieme ordinato delle migrazioni, la configurazione delle locale e l’esecutore di migrazioni dell’adapter usati da quella build.
Esegui questi comandi dal progetto le cui dipendenze hanno prodotto il manifest. Prima compila e ispeziona la destinazione.
pnpm build
pnpm emdash migrate --status
Dopo aver confermato che la destinazione riportata è il database previsto, avvia la migrazione interattiva. Rivedi di nuovo la destinazione al prompt prima di confermare. Poi esegui il deploy della stessa build e verifica lo schema distribuito.
pnpm emdash migrate
pnpm wrangler deploy
pnpm emdash migrate --check
emdash migrate --status segnala le migrazioni applicate, in sospeso e sconosciute senza modificare il database. Il semplice comando emdash migrate mostra la destinazione e chiede conferma prima di applicare le migrazioni in sospeso.
--check non applica mai migrazioni e termina con un codice diverso da zero quando ci sono migrazioni note in sospeso o quando il database contiene record di migrazione sconosciuti alla build. Usa --status quando vuoi ispezionare gli stessi insiemi di migrazioni senza lo stato di uscita diverso da zero di check, che indica «lavoro necessario». Il riferimento della CLI distingue i codici di uscita per in sospeso, sconosciuto, conferma, interruzione ed errore operativo.
L’applicazione non interattiva e ogni applicazione con --json richiedono --expected-target-fingerprint; il comando fallisce se la destinazione risolta non corrisponde. Usa queste opzioni nei job di deployment automatizzati, non nel flusso interattivo descritto sopra.
Usa --manifest path/to/migrations.json per un manifest memorizzato altrove. Per un’indagine locale, --from-config [--config astro.config.mjs] valuta esplicitamente la configurazione di un progetto fidato, senza eseguire gli hook di Astro né avviare un server. Le pipeline di deployment dovrebbero consumare il manifest della build.
Selezionare il database esplicitamente
L’adapter configurato fornisce al manifest informazioni sulla destinazione prive di segreti. Le credenziali restano nelle variabili d’ambiente e vengono lette solo dal comando di migrazione.
| Adapter | Destinazione nel manifest | Variabile di credenziali predefinita | Override utile |
|---|---|---|---|
| SQLite | Percorso del database o URL file: | — | --database <path> |
| libSQL | URL pubblico | TURSO_AUTH_TOKEN | Configura migrationAuthTokenEnv |
| PostgreSQL | Nome della variabile di connessione | DATABASE_URL | --database-url-env <name> |
| Cloudflare D1 | Nome del binding di Wrangler | CLOUDFLARE_API_TOKEN | --d1, --account-id, --wrangler-config, --wrangler-env |
| Hyperdrive | Binding primario e nome della variabile dell’origine | Variabile dell’origine diretta specifica del binding | Configura migrationConnectionStringEnv |
I percorsi SQLite relativi vengono risolti dalla radice del progetto, non dal pacchetto EmDash installato né dalla sottodirectory corrente della shell. Le etichette di destinazione per PostgreSQL, libSQL e Hyperdrive omettono le credenziali e i parametri dell’URL.
Provisionare D1 prima di migrarlo
Creare un database D1 e migrarne lo schema sono operazioni distinte. emdash migrate non crea mai un database mancante.
-
Effettua il provisioning del database e annota il suo UUID di produzione.
pnpm wrangler d1 create my-site-production -
Aggiungi quell’UUID al binding e all’ambiente previsti in
wrangler.jsonc. -
Compila il sito in modo che il binding D1 venga registrato in
.emdash/migrations.json. -
Imposta l’ID dell’account e un token API con ambito limitato e permesso D1 Edit. Ispeziona la destinazione selezionata, poi esegui la migrazione interattiva. Conferma il prompt solo quando l’account e il database corrispondono al database di produzione previsto.
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
In alternativa puoi fornire --account-id insieme a --d1 <database-uuid-or-name>. La ricerca per nome deve risolversi in esattamente un database. ID di anteprima, ID segnaposto, account in conflitto e binding ambigui falliscono in modo sicuro (fail closed).
Configurare le migrazioni D1 in CI
EmDash mantiene un lock di migrazione nel database D1 mentre applica le migrazioni, sia da emdash migrate sia dalle migrazioni a runtime in modalità auto. Una seconda esecuzione che parte mentre il lock è mantenuto attende fino a 10 secondi. Se la prima esecuzione termina in quel tempo, la seconda riesce senza applicare nulla; altrimenti fallisce senza applicare migrazioni. Esegui un solo job di migrazione alla volta per account e UUID del database, così un secondo job attende nella coda della CI invece di fallire.
Imposta il seguente segreto e le seguenti variabili nell’ambiente di CI:
- Segreto
CLOUDFLARE_API_TOKEN: un token con ambito limitato e permesso D1 Edit. - Variabile
CLOUDFLARE_ACCOUNT_ID: l’ID dell’account Cloudflare proprietario del database. - Variabile
D1_DATABASE_ID: l’UUID del database D1 di produzione. - Variabile
EMDASH_TARGET_FINGERPRINT: l’impronta stampata daemdash migrate --statusdopo che hai rivisto localmente l’account e il database.
Il seguente workflow di GitHub Actions usa questi valori e compone la chiave del gruppo di concorrenza con entrambi gli identificatori D1 immutabili. Il suo passo di applicazione non è interattivo, quindi fornisce esplicitamente l’impronta della destinazione rivista.
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 }}"
Aggiorna EMDASH_TARGET_FINGERPRINT solo dopo aver rivisto localmente una destinazione modificata. L’impronta non contiene alcuna credenziale, ma modificarla senza verificare l’account e il database elimina la salvaguardia contro la migrazione del database sbagliato.
Rilasciare un lock di migrazione bloccato
Un’esecuzione di migrazione D1 che si interrompe prima di rilasciare il lock di migrazione lascia il lock mantenuto. Succede quando un job di CI viene annullato durante emdash migrate, quando un Worker in modalità auto si ferma durante una migrazione a runtime, o quando un server di sviluppo viene fermato mentre applica le migrazioni. Un’esecuzione che fallisce con un errore di migrazione rilascia il lock. EmDash non rilascia un lock che non detiene, perché il detentore potrebbe ancora applicare migrazioni o potrebbe essersi fermato a metà di una. Finché il lock non viene rilasciato, il sito non può applicare le proprie migrazioni in sospeso e, in modalità auto, EmDash non riesce a inizializzarsi.
Quando il lock è mantenuto da più di un minuto, emdash migrate e le migrazioni a runtime smettono di attenderlo e segnalano il seguente errore:
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
Rilasciare il lock di un database D1 remoto usa emdash migrate, quindi richiede una build che abbia scritto .emdash/migrations.json e un token API con permesso D1 Edit, come descritto in Provisionare D1 prima di migrarlo.
-
Verifica che nessun job di migrazione, deployment o altro comando
emdash migratesia in esecuzione sul database. -
Ispeziona il lock e gli insiemi di migrazioni con le stesse opzioni di destinazione usate dalla migrazione.
pnpm emdash migrate --statusIl report inizia con il lock e il suo id. Se l’esecuzione interrotta stava applicando una migrazione, quella era la prima migrazione in sospeso e potrebbe essere stata applicata solo in parte.
Migration lock: held since 2026-09-01T12:00:00.000Z (id 1788264000000)Anche un Worker in modalità
autopuò mantenere il lock mentre applica le migrazioni. Esegui di nuovo il comando dopo un minuto o più e, finché le migrazioni applicate note continuano a cambiare, attendi invece di rilasciare il lock. -
Rilascia il lock con quell’id. Il comando ti chiede di confermare la destinazione e rilascia il lock solo finché ha ancora quell’id. In una shell non interattiva, aggiungi
--expected-target-fingerprintcon l’impronta della destinazione stampata da--status.pnpm emdash migrate --release-lock 1788264000000 -
Applica di nuovo le migrazioni in sospeso.
pnpm emdash migrateSe l’applicazione fallisce nella prima migrazione in sospeso, considera quella migrazione lasciata a metà e segui la voce sulla scrittura D1 ambigua in Risoluzione dei problemi.
emdash migrate raggiunge solo i database D1 remoti. Quando il lock è mantenuto nel database D1 locale di un server di sviluppo, ferma il server e cancella il lock con Wrangler, sostituendo DB con il nome del binding e il numero con l’id del lock riportato nell’errore.
pnpm wrangler d1 execute DB --local --command "UPDATE _emdash_migrations_lock SET is_locked = 0 WHERE is_locked = 1788264000000"
Hyperdrive si connette all’origine
L’esecutore di migrazioni di Hyperdrive apre una connessione PostgreSQL diretta all’origine. Non instrada il traffico di migrazione attraverso Hyperdrive, non usa il binding di cache opzionale e non eredita dal Worker la raggiungibilità della rete privata.
Il runner del deployment deve poter raggiungere l’origine. Imposta migrationConnectionStringEnv su hyperdrive() quando la variabile predefinita specifica del binding non è adatta, e fornisci quella variabile solo al job di migrazione. Tieni separate le credenziali Hyperdrive del runtime e le credenziali di deployment per l’origine diretta.
Adottare gradualmente il controllo obbligatorio a runtime
La seguente configurazione dell’integrazione EmDash abilita il controllo obbligatorio a runtime mantenendo le migrazioni automatiche in sviluppo.
emdash({
database,
migrations: {
runtime: "check",
dev: "auto",
},
});
autoè il valore predefinito retrocompatibile. L’avvio a runtime controlla e applica le migrazioni in sospeso.checkesegue una query di stato direzionale e restituisce 503 prima di servire una richiesta quando ci sono migrazioni note in sospeso. Tollera i record di una build compatibile più recente durante un rolling deployment. Le richieste all’endpoint delle immagini che EmDash installa continuano a essere servite, perché saltano l’avvio a runtime che esegue questo controllo.manualnon esegue alcuna migrazione né query di stato a runtime. Usalo solo dopo che la pipeline di deployment applica e verifica ogni build in modo affidabile.
EMDASH_MIGRATIONS_MODE può sovrascrivere la modalità di runtime quando lo stesso artefatto viene promosso attraverso più ambienti. Le rotte di bypass di setup e sviluppo rispettano la modalità effettiva; non possono migrare in silenzio dietro check o manual.
Un’introduzione prudente è auto mentre introduci il job di deployment, poi check quando il job è affidabile, e infine manual quando per ogni deployment viene imposta una verifica esterna.
Compatibilità durante i rolling deploy
Le migrazioni core seguono la sequenza expand/deploy/contract (espandere/distribuire/contrarre). Un deployment può eseguire temporaneamente isolate vecchi e nuovi dell’applicazione sul database espanso, e un backfill potrebbe essere ancora in corso. Non contrarre uno schema finché ogni versione distribuita non ha smesso di usarlo.
I record di migrazioni applicate sconosciuti sono tollerati dal check a runtime solo per questa direzione del rolling deployment. La verifica esatta della CLI li segnala e l’applicazione si rifiuta di modificare qualcosa, perché il database potrebbe essere più recente o avere una cronologia di migrazioni divergente.
Limite di rollback
Distribuire l’artefatto precedente dell’applicazione non annulla una migrazione core. Prima di applicare le migrazioni in sospeso, esegui un backup ripristinabile del database e annota l’artefatto dell’applicazione che gli corrisponde. Se l’applicazione precedente non può funzionare con lo schema migrato, ripristina insieme il database precedente alla migrazione e l’applicazione. Non eliminare righe da _emdash_migrations e non eseguire la funzione interna down() di una migrazione come rollback operativo.
Riparare la proprietà PostgreSQL mista
Usa questo runbook quando un sito PostgreSQL esistente ha creato oggetti EmDash con più di un proprietario e le migrazioni successive falliscono con errori come must be owner of table. Scegli il ruolo canonico che la connessione primaria di EmDash continuerà a usare. Esegui un backup ripristinabile del database e ferma il traffico dell’applicazione e le modifiche allo schema prima di cambiare la proprietà.
Ispeziona ogni tabella dello schema attivo:
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;
Gli oggetti EmDash includono le tabelle di sistema _emdash_* e _plugin_*, le tabelle di collezione ec_* e tabelle senza prefisso come content_taxonomies, media, options, revisions e taxonomies. In uno schema EmDash dedicato, ogni tabella dell’applicazione dovrebbe avere il proprietario canonico.
EmDash crea anche funzioni PostgreSQL usate dai trigger sull’utilizzo dei media. Ispeziona la proprietà delle funzioni e conserva la firma degli argomenti di ciascuna funzione per il comando di riparazione:
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;
Trasferisci ogni oggetto non corrispondente con un superuser o un ruolo del provider che possa modificarne la proprietà. Usa lo schema, l’oggetto, il ruolo e la firma della funzione reali dell’inventario invece di copiare senza modifiche i nomi dell’esempio:
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;
Cambiare il proprietario di una tabella copre anche i suoi indici, vincoli e trigger collegati, ma non le funzioni trigger indipendenti. Ripeti entrambe le query di inventario finché ogni tabella e funzione di EmDash non riporta il proprietario canonico. Poi connettiti con quel ruolo e verifica current_database(), current_schema() e lo stato delle migrazioni prima di riprendere il traffico.
Perché un utente che non è superuser possa trasferire la proprietà, deve possedere l’oggetto o ereditarne la proprietà, poter eseguire SET ROLE verso il nuovo proprietario, e il nuovo proprietario deve avere CREATE sullo schema. I provider di PostgreSQL gestito possono richiedere che il trasferimento venga eseguito dal loro ruolo amministrativo.
Risoluzione dei problemi
- Nessun manifest di migrazione trovato. Compila o sincronizza prima il progetto. Usa
--manifestper una posizione non standard dell’artefatto oppure scegli esplicitamente--from-configper un’indagine locale. - L’artefatto non corrisponde all’EmDash del progetto. Ricompila ed esegui il deploy insieme di applicazione e manifest. Esegui la CLI del progetto invece di un’installazione globale.
- La destinazione è mancante o ambigua. Effettua prima il provisioning, poi fornisci un percorso del database esplicito, il nome della variabile di connessione, un selettore D1 o la configurazione di Wrangler e l’ambiente selezionati. EmDash non tira a indovinare da variabili d’ambiente o binding non correlati.
- L’impronta della destinazione è cambiata. Fermati e verifica l’account, l’ambiente, il nome del database, l’UUID o il percorso mostrati. Aggiorna l’impronta attesa solo dopo aver confermato la destinazione prevista.
- Sono presenti record di migrazione sconosciuti. Non eliminare i record e non rieseguire l’applicazione. Conferma che l’artefatto dell’applicazione sia la versione prevista e indaga se una build più recente o divergente abbia migrato il database.
- L’esito di una scrittura D1 è ambiguo. Non rieseguire il comando di migrazione. Esegui
emdash migrate --statussullo stesso account e sullo stesso UUID del database, ispeziona il risultato e inoltra il problema se la migrazione si è fermata a metà. - La normalizzazione di data e ora richiede una revisione manuale. Una data e ora legacy cade in un’ora ripetuta o saltata per l’ora legale nel fuso orario configurato del sito. L’errore elenca ogni riga di contenuto o revisione interessata. Correggi quei valori con un offset UTC esplicito, poi riprova la migrazione. Il controllo preliminare della migrazione non scrive alcuna data e ora finché ogni valore memorizzato non può essere risolto.
- Hyperdrive non riesce a connettersi. Verifica la raggiungibilità dell’origine PostgreSQL dal runner del deployment e controlla la variabile dell’origine diretta. La connettività tra Worker e Hyperdrive non dimostra che il runner possa raggiungere l’origine.