As migrações do núcleo do EmDash atualizam as tabelas do próprio EmDash e as colunas padrão das tabelas de conteúdo. Elas não criam, removem nem renomeiam suas coleções e campos; consulte Evoluir o esquema de um site implantado para mudanças no modelo de conteúdo.
O modo de migração em tempo de execução é auto por padrão, então as implantações existentes continuam aplicando as migrações pendentes do núcleo na inicialização. As migrações gerenciadas pela implantação permitem que um build migre seu banco de dados antes de o novo código da aplicação receber tráfego, e depois que o tempo de execução verifique esse passo da implantação ou confie nele.
As migrações do núcleo só avançam. Elas são escritas de modo que um comando possa ser repetido depois de instruções que certamente foram concluídas, mas um comando remoto interrompido pode deixar um resultado ambíguo. A resposta segura é inspecionar o mesmo banco de dados com emdash migrate --status, em vez de presumir que a migração inteira, ou nenhuma parte dela, foi executada.
Compilar, migrar, implantar, verificar
Um build ou uma sincronização do Astro grava .emdash/migrations.json. Esse manifesto, sem segredos, registra a versão exata do EmDash, o conjunto ordenado de migrações, a configuração de locales e o executor de migrações do adaptador usados por aquele build.
Execute estes comandos a partir do projeto cujas dependências produziram o manifesto. Primeiro compile e inspecione o destino.
pnpm build
pnpm emdash migrate --status
Depois de confirmar que o destino informado é o banco de dados pretendido, inicie a migração interativa. Revise o destino novamente no prompt antes de confirmar. Em seguida, implante o mesmo build e verifique o esquema implantado.
pnpm emdash migrate
pnpm wrangler deploy
pnpm emdash migrate --check
emdash migrate --status informa as migrações aplicadas, pendentes e desconhecidas sem alterar o banco de dados. O comando emdash migrate simples exibe o destino e pede confirmação antes de aplicar as migrações pendentes.
--check nunca aplica migrações e termina com código diferente de zero quando há migrações conhecidas pendentes ou quando o banco de dados contém registros de migração desconhecidos para o build. Use --status quando quiser inspecionar os mesmos conjuntos de migrações sem o status de saída diferente de zero do check, que indica “há trabalho a fazer”. A referência da CLI distingue os códigos de saída de pendente, desconhecido, confirmação, interrupção e erro operacional.
A aplicação não interativa e toda aplicação com --json exigem --expected-target-fingerprint; o comando falha se o destino resolvido não corresponder. Use essas opções em jobs de implantação automatizados, não no fluxo interativo acima.
Use --manifest path/to/migrations.json para um manifesto armazenado em outro lugar. Para uma investigação local, --from-config [--config astro.config.mjs] avalia explicitamente a configuração de um projeto confiável, sem executar os hooks do Astro nem iniciar um servidor. Os pipelines de implantação devem consumir o manifesto do build.
Selecionar o banco de dados explicitamente
O adaptador configurado fornece ao manifesto informações do destino sem segredos. As credenciais permanecem em variáveis de ambiente e são lidas apenas pelo comando de migração.
| Adaptador | Destino do manifesto | Variável de credencial padrão | Substituição útil |
|---|---|---|---|
| SQLite | Caminho do banco de dados ou URL file: | — | --database <path> |
| libSQL | URL pública | TURSO_AUTH_TOKEN | Configure migrationAuthTokenEnv |
| PostgreSQL | Nome da variável de conexão | DATABASE_URL | --database-url-env <name> |
| Cloudflare D1 | Nome do binding do Wrangler | CLOUDFLARE_API_TOKEN | --d1, --account-id, --wrangler-config, --wrangler-env |
| Hyperdrive | Binding primário e nome da variável da origem | Variável de origem direta específica do binding | Configure migrationConnectionStringEnv |
Caminhos relativos do SQLite são resolvidos a partir da raiz do projeto, não do pacote EmDash instalado nem do subdiretório atual do shell. Os rótulos de destino de PostgreSQL, libSQL e Hyperdrive omitem credenciais e parâmetros de URL.
Provisionar D1 antes de migrá-lo
Criar um banco de dados D1 e migrar seu esquema são operações separadas. emdash migrate nunca cria um banco de dados ausente.
-
Provisione o banco de dados e anote seu UUID de produção.
pnpm wrangler d1 create my-site-production -
Adicione esse UUID ao binding e ao ambiente pretendidos em
wrangler.jsonc. -
Compile o site para que o binding do D1 seja registrado em
.emdash/migrations.json. -
Defina o ID da conta e um token de API com escopo limitado e permissão D1 Edit. Inspecione o destino selecionado e depois execute a migração interativa. Confirme o prompt somente quando a conta e o banco de dados corresponderem ao banco de dados de produção pretendido.
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
Você também pode fornecer --account-id com --d1 <database-uuid-or-name>. A busca por nome deve resolver exatamente um banco de dados. IDs de preview, IDs de espaço reservado, contas conflitantes e bindings ambíguos falham de forma segura (fail closed).
Configurar migrações D1 no CI
O EmDash mantém um bloqueio de migração no banco de dados D1 enquanto aplica migrações, tanto a partir de emdash migrate quanto das migrações em tempo de execução no modo auto. Uma segunda execução que começa enquanto o bloqueio está retido espera até 10 segundos. Se a primeira execução terminar nesse tempo, a segunda é bem-sucedida sem aplicar nada; caso contrário, falha sem aplicar migrações. Execute um job de migração por vez para cada conta e UUID de banco de dados, para que um segundo job espere na fila do CI em vez de falhar.
Defina o seguinte segredo e as seguintes variáveis no ambiente de CI:
- Segredo
CLOUDFLARE_API_TOKEN: um token com escopo limitado e permissão D1 Edit. - Variável
CLOUDFLARE_ACCOUNT_ID: o ID da conta da Cloudflare proprietária do banco de dados. - Variável
D1_DATABASE_ID: o UUID do banco de dados D1 de produção. - Variável
EMDASH_TARGET_FINGERPRINT: a impressão digital exibida poremdash migrate --statusdepois que você revisar localmente a conta e o banco de dados.
O seguinte workflow do GitHub Actions usa esses valores e compõe a chave do grupo de concorrência com os dois identificadores imutáveis do D1. Seu passo de aplicação não é interativo, então ele fornece explicitamente a impressão digital do destino revisada.
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 }}"
Atualize EMDASH_TARGET_FINGERPRINT somente depois de revisar localmente um destino alterado. A impressão digital não contém nenhuma credencial, mas alterá-la sem verificar a conta e o banco de dados remove a salvaguarda contra migrar o banco de dados errado.
Liberar um bloqueio de migração preso
Uma execução de migração do D1 que para antes de liberar o bloqueio de migração deixa o bloqueio retido. Isso acontece quando um job de CI é cancelado durante emdash migrate, quando um Worker no modo auto para durante uma migração em tempo de execução, ou quando um servidor de desenvolvimento é interrompido enquanto aplica migrações. Uma execução que falha com um erro de migração libera o bloqueio. O EmDash não libera um bloqueio que não detém, porque o detentor pode ainda estar aplicando migrações ou pode ter parado no meio de uma. Enquanto o bloqueio não for liberado, o site não consegue aplicar suas migrações pendentes e, no modo auto, o EmDash falha ao inicializar.
Depois que o bloqueio permanece retido por mais de um minuto, emdash migrate e as migrações em tempo de execução deixam de esperar por ele e informam o seguinte erro:
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
Liberar o bloqueio de um banco de dados D1 remoto usa emdash migrate, então é necessário um build que tenha gravado .emdash/migrations.json e um token de API com permissão D1 Edit, como descrito em Provisionar D1 antes de migrá-lo.
-
Confirme que nenhum job de migração, implantação ou outro comando
emdash migrateestá em execução no banco de dados. -
Inspecione o bloqueio e os conjuntos de migrações com as mesmas opções de destino que a migração usou.
pnpm emdash migrate --statusO relatório começa com o bloqueio e seu id. Se a execução interrompida estava aplicando uma migração, essa foi a primeira migração pendente e ela pode ter sido aplicada parcialmente.
Migration lock: held since 2026-09-01T12:00:00.000Z (id 1788264000000)Um Worker no modo
autotambém pode reter o bloqueio enquanto aplica migrações. Execute o comando novamente um minuto ou mais depois e, enquanto as migrações aplicadas conhecidas continuarem mudando, espere em vez de liberar o bloqueio. -
Libere o bloqueio com esse id. O comando pede que você confirme o destino e libera o bloqueio somente enquanto ele ainda tiver esse id. Em um shell não interativo, adicione
--expected-target-fingerprintcom a impressão digital do destino exibida por--status.pnpm emdash migrate --release-lock 1788264000000 -
Aplique novamente as migrações pendentes.
pnpm emdash migrateSe a aplicação falhar na primeira migração pendente, trate essa migração como deixada pela metade e siga a entrada sobre uma gravação ambígua no D1 em Solução de problemas.
emdash migrate alcança apenas bancos de dados D1 remotos. Quando o bloqueio está retido no banco de dados D1 local de um servidor de desenvolvimento, pare o servidor e limpe o bloqueio com o Wrangler, substituindo DB pelo nome do binding e o número pelo id do bloqueio mostrado no erro.
pnpm wrangler d1 execute DB --local --command "UPDATE _emdash_migrations_lock SET is_locked = 0 WHERE is_locked = 1788264000000"
Hyperdrive conecta-se à origem
O executor de migrações do Hyperdrive abre uma conexão direta de PostgreSQL com a origem. Ele não envia o tráfego de migração pelo Hyperdrive, não usa o binding de cache opcional e não herda do Worker a alcançabilidade da rede privada.
O runner da implantação precisa conseguir alcançar a origem. Defina migrationConnectionStringEnv em hyperdrive() quando a variável padrão específica do binding não for adequada, e forneça essa variável somente ao job de migração. Mantenha separadas as credenciais do Hyperdrive em tempo de execução e as credenciais de implantação da origem direta.
Adotar gradualmente a exigência em tempo de execução
A seguinte configuração da integração do EmDash habilita a exigência em tempo de execução e mantém as migrações automáticas em desenvolvimento.
emdash({
database,
migrations: {
runtime: "check",
dev: "auto",
},
});
autoé o padrão retrocompatível. A inicialização em tempo de execução verifica e aplica as migrações pendentes.checkexecuta uma consulta de status direcional e retorna 503 antes de atender uma requisição quando há migrações conhecidas pendentes. Ele tolera registros de um build compatível mais novo durante uma implantação gradual. As requisições ao endpoint de imagens que o EmDash instala continuam sendo atendidas, porque pulam a inicialização em tempo de execução que executa essa verificação.manualnão executa nenhuma migração nem consulta de status em tempo de execução. Use-o somente depois que o pipeline de implantação aplicar e verificar cada build de forma confiável.
EMDASH_MIGRATIONS_MODE pode substituir o modo de execução quando o mesmo artefato é promovido por vários ambientes. As rotas de desvio de configuração e desenvolvimento obedecem ao modo efetivo; elas não podem migrar silenciosamente por trás de check ou manual.
Uma introdução conservadora é auto enquanto você introduz o job de implantação, depois check quando o job estiver confiável e, por fim, manual quando uma verificação externa for imposta em toda implantação.
Compatibilidade durante implantações graduais
As migrações do núcleo seguem a sequência expandir/implantar/contrair (expand/deploy/contract). Uma implantação pode executar temporariamente isolates antigos e novos da aplicação sobre o banco de dados expandido, e um preenchimento retroativo (backfill) ainda pode estar em andamento. Não contraia um esquema até que todas as versões implantadas tenham parado de usá-lo.
Registros de migrações aplicadas desconhecidos são tolerados pelo check em tempo de execução apenas para essa direção da implantação gradual. A verificação exata da CLI os informa e a aplicação se recusa a modificar qualquer coisa, porque o banco de dados pode ser mais novo ou ter um histórico de migrações divergente.
Limite de reversão
Implantar o artefato anterior da aplicação não reverte uma migração do núcleo. Antes de aplicar as migrações pendentes, faça um backup restaurável do banco de dados e anote o artefato da aplicação que corresponde a ele. Se a aplicação anterior não conseguir executar com o esquema migrado, restaure juntos o banco de dados anterior à migração e a aplicação. Não exclua linhas de _emdash_migrations nem execute a função interna down() de uma migração como reversão operacional.
Reparar propriedade PostgreSQL mista
Use este runbook quando um site PostgreSQL existente tiver criado objetos do EmDash com mais de um proprietário e as migrações seguintes falharem com erros como must be owner of table. Escolha o papel canônico que a conexão primária do EmDash continuará usando. Faça um backup restaurável do banco de dados e pare o tráfego da aplicação e as alterações de esquema antes de mudar a propriedade.
Inspecione todas as tabelas do esquema ativo:
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;
Os objetos do EmDash incluem as tabelas de sistema _emdash_* e _plugin_*, as tabelas de coleção ec_* e tabelas sem prefixo, como content_taxonomies, media, options, revisions e taxonomies. Em um esquema dedicado do EmDash, toda tabela da aplicação deve ter o proprietário canônico.
O EmDash também cria funções do PostgreSQL usadas pelos triggers de uso de mídia. Inspecione a propriedade das funções e guarde a assinatura de argumentos de cada função para o comando de reparo:
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;
Transfira cada objeto divergente com um superusuário ou um papel do provedor que possa alterar a propriedade. Use o esquema, o objeto, o papel e a assinatura de função reais do inventário em vez de copiar os nomes do exemplo sem alterações:
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;
Alterar o proprietário de uma tabela também abrange seus índices, restrições e triggers associados, mas não as funções de trigger independentes. Repita as duas consultas de inventário até que toda tabela e função do EmDash informe o proprietário canônico. Depois, conecte-se com esse papel e verifique current_database(), current_schema() e o status das migrações antes de reiniciar o tráfego.
Para que um usuário que não é superusuário transfira a propriedade, ele precisa possuir o objeto ou herdar sua propriedade, poder executar SET ROLE para o novo proprietário, e o novo proprietário precisa ter CREATE no esquema. Provedores de PostgreSQL gerenciado podem exigir que o papel administrativo deles realize a transferência.
Solução de problemas
- Nenhum manifesto de migração encontrado. Compile ou sincronize o projeto primeiro. Use
--manifestpara um local de artefato fora do padrão ou escolha explicitamente--from-configpara uma investigação local. - O artefato não corresponde ao EmDash do projeto. Recompile e implante a aplicação e o manifesto juntos. Execute a CLI do projeto em vez de uma instalação global.
- O destino está ausente ou é ambíguo. Provisione-o primeiro e depois forneça um caminho de banco de dados explícito, o nome da variável de conexão, um seletor do D1 ou a configuração do Wrangler e o ambiente selecionados. O EmDash não adivinha a partir de variáveis de ambiente ou bindings não relacionados.
- A impressão digital do destino mudou. Pare e revise a conta, o ambiente, o nome do banco de dados, o UUID ou o caminho exibidos. Atualize a impressão digital esperada somente depois de confirmar o destino pretendido.
- Há registros de migração desconhecidos. Não exclua os registros nem execute a aplicação novamente. Confirme que o artefato da aplicação é a versão pretendida e investigue se um build mais novo ou divergente migrou o banco de dados.
- O resultado de uma gravação no D1 é ambíguo. Não repita o comando de migração. Execute
emdash migrate --statusna mesma conta e no mesmo UUID de banco de dados, inspecione o resultado e escale o problema se a migração parou no meio. - A normalização de data e hora exige revisão manual. Uma data e hora legada cai em uma hora repetida ou ignorada pelo horário de verão no fuso horário configurado do site. O erro lista cada linha de conteúdo ou revisão afetada. Corrija esses valores com um deslocamento UTC explícito e tente a migração novamente. A verificação prévia da migração não grava nenhuma data e hora até que todo valor armazenado possa ser resolvido.
- O Hyperdrive não consegue se conectar. Teste a alcançabilidade da origem do PostgreSQL a partir do runner da implantação e verifique a variável de origem direta. A conectividade entre o Worker e o Hyperdrive não prova que o runner consegue alcançar a origem.