I have several n8n workflows that can run for 10–30 minutes, and they all use the same PostgreSQL tables.
I need to change the database schema, but some older workflow executions may still be using the old structure when the migration happens.
For example, I might rename or remove a column:
ALTER TABLE orders
DROP COLUMN legacy_status;
A workflow that started before the migration could still expect that column to exist.
Would you keep the old column temporarily, deploy the new workflow first, wait for existing executions to finish, and then remove the old schema?
Or is there a better migration strategy for long-running n8n workflows?
Describe the problem/error/question
What is the error message (if any)?
Please share your workflow
(Select the nodes on your canvas and use the keyboard shortcuts CMD+C/CTRL+C and CMD+V/CTRL+V to copy and paste the workflow.)
Hi @Roseline The safest approach is to make the database support both versions for a while.
For example, instead of immediately dropping legacy_status, i would first add the replacement:
ALTER TABLE orders
ADD COLUMN status_v2 TEXT;
Then deploy the updated workflow so new executions use status_v2, while older executions can still use legacy_status.
Add New Column
Deploy New Workflow
Old + New Versions Run Safely
Wait for Old Executions
Migrate Remaining Data
Remove Old Column
For larger changes, I would also keep track of the schema/workflow version:
ALTER TABLE orders
ADD COLUMN schema_version INTEGER NOT NULL DEFAULT 1;
That can be useful when troubleshooting records created by different workflow versions.
Also avoid relying only on a fixed waiting period. Before removing the old column, check that there are no active executions or processes still depending on it.
The main idea is don’t make the migration and workflow deployment a single breaking change. Make the schema backward compatible first, move the workflows over, verify everything is using the new structure, and only then clean up the old column.
Yes, keep the old column until nothing can use it anymore. Include executions paused at a Wait node and retries using the old workflow, not just currently running executions. If you’re only removing legacy_status, you don’t need a replacement column.
For a rename, one thing to change in the sequence above: backfill the new column and keep writes synchronized BEFORE switching reads to it. Otherwise the new workflow can read empty or outdated values.
Updating both columns only in the new workflow won’t cover older executions still writing legacy_status. You can keep that column as the write source temporarily and use a PostgreSQL trigger to sync the replacement. Once the old executions and rollback window are cleared, switch writes too, then remove the old column and temporary sync.
Both community members @Anshul_Namdev and @Emmas gave correct, industry-standard advice. In n8n, active or paused executions (such as those at a Wait node) retain their original configuration mid-run. Altering the database schema mid-execution will cause these long-running tasks to fail.
Here is the combined, step-by-step migration strategy written in concise sequence:
Step 1: Add the new column without breaking changes. Run an ALTER TABLE command to add the new column to your database, keeping the old column completely intact.
Step 2: Set up a database trigger for synchronization. Create a PostgreSQL trigger to copy any data written to the old column over to the new column automatically. This protects long-running workflows that are still active and writing to the old schema.
Step 3: Backfill your existing data. Run a script to copy historical data from the old column into the new column for all existing records.
Step 4: Deploy your updated n8n workflow. Update and publish your new n8n workflow so that all fresh executions natively target the new column.
Step 5: Monitor and wait out your active executions. Check the n8n Executions panel. Wait until all older executions, retries, and paused Wait nodes have entirely finished running.
Step 6: Safely remove the legacy column. Delete the temporary database trigger and drop the old column from your database schema once no traffic is using it.