Simplify your stack and build anything. Or everything.
Build tomorrow’s web with a modern solution you truly own.
Code-based nature means you can build on top of it to power anything.
It’s time to take back your content infrastructure.

Production Migration Strategy Questions

default discord avatar
justinthomas544212 months ago
4

Hey Payload community, I'm working on a Payload site and would love some guidance on production migration workflows, especially for complex schema changes.



My main concerns:



1. Destructive Changes in Production


- What happens when I remove a field/collection that production data is still using?



- Let's say 5 months from now I delete a field, but my live site has thousands of records with that data



I- s there a recommended workflow for handling these "breaking changes" safely?


Do I need to write custom cleanup migrations, or does Payload handle orphaned data gracefully?



2. Mixed Add/Remove Operations


- How do you handle migrations that both add AND remove things simultaneously?



- What's the safest order of operations? (Remove fields first, then add? Vice versa?)



- Any gotchas when production has active users during migration deployment?


3. Database-Specific Differences


- Is there a difference in migration workflow between MongoDB vs PostgreSQL?



- Do both handle schema changes the same way, or are there DB-specific considerations?



- Any performance implications I should know about for either?



4. Safety Net Strategies


- What's your backup/rollback strategy before running migrations?



- Do you use staging environments that mirror production data volume?



- Any tools or practices for "dry run" testing migrations?




Current Setup:


Database: MongoDB


Framework: Next.js 15.3.0 + Payload 3.40.0


Deployment: Dokploy with Nixpacks


Migration workflow: payload migrate:create locally → push to repo → Nixpacks runs pnpm build && payload migrate && next start on deploy


(I have a nixpacks.toml file with cmd = "cross-env NODE_OPTIONS=--no-deprecation pnpm build && cross-env NODE_OPTIONS=--no-deprecation payload migrate && cross-env NODE_OPTIONS=--no-deprecation next start"



Payload migrate happens right before next start), which means if something goes wrong with a migration, my entire site could go down during the deploy process. 😅

  • default discord avatar
    lord.vulcan12 months ago

    not 100% sure on this but i think the underlying data wouldn't be deleted, it just wouldn't be transferred.



    so if you rename a field for example, you'd need a custom migration script to pull the data hitting mongodb directly, and then loading it back into payload via the api into the new field.



    yes there's a difference in migration workflow with mongo vs postgres. it's a lot harder to maintain dev prod consistency with postgres. when i came to payload I had an antiquated/imprecise mindset of NoSQL bad, SQL good, so went with postgres, quickly switched to Mongo with migration pain, and I'm very glad I did so.



    safety net strategies: I have a cron job set up to back up production mongo daily to s3. then I have a dev server which loads in that data every day from s3. so when i'm developing locally, i point at the dev server.



    IMO easier workflow than having mongo locally . takes a little dev ops chops but if you use llms for help its not too bad



    *with postgres migration pain

  • default discord avatar
    themachine048812 months ago

    Lets say you have done this change your collection:



    // Old


    {


    title: "Post title",


    summary: "Some text"


    }



    // New


    {


    title: "Post title",


    description: "Some text"


    }



    With MongoDB you’d have two choices.



    1. Adjust your code to respect the old and new structure (not scalable)



    2. Write a migration that copies copies the values to the new field from the old field. Remove the old field.



    In my experience with MongoDB, you just end up with wanting to do SQL things with a non-SQL DB after a while.



    My best tip is to use postgres but with push mode disabled locally. That will make you understand migrations better. It’s basically just version control for your DB.

  • discord user avatar
    seanzubrickas
    12 months ago

    Hey

    @1063733963476181082

    I answered your post on Reddit too, but just to make sure I've covered our bases, or if anyone on here is curious:



    1. Destructive Changes in Production



    What happens when I remove a field/collection that production data is still using?



    Let's say 5 months from now I delete a field, but my live site has thousands of records with that data



    Is there a recommended workflow for handling these "breaking changes" safely?



    Do I need to write custom cleanup migrations, or does Payload handle orphaned data gracefully?



    All of these questions heavily rely on which database you’re using. MongoDB is a lot easier to deal with, but in the relational world you are going to have more steps involved.



    With MongoDB if you remove a field or a collection, it does not drop the data. You would need to manually delete that stuff out of your database if you wanted to clean it up. With Postgres or SQLite, if you remove a field, then it will indeed drop the column from your database, and that data will be lost.



    With MongoDB you can create a payload migration and leverage the MongoDB connection directly to clean up any old data—in Postgres, Payload automatically creates migrations for you by diffing your schema before and after changes, and cleaning up data for you.



    https://payloadcms.com/docs/database/migrations

    2. Mixed Add/Remove Operations



    How do you handle migrations that both add AND remove things simultaneously? What's the safest order of operations?



    You can generally add and remove fields at the same time, but your question might be targeted towards copying data from one column into another column. A good approach would be to add the new column, migrate the data from the old column to the new column, and then drop the old column.



    Any gotchas when production has active users during migration deployment?



    Depending on your expected migration time, if they're quick and non-destructive, you can just run them against production. However, if they're more significant and take more time to run, then you might consider running them against a staging database, making sure that your database is fully set to go, and then swapping the connection string, or renaming the database so it is a quick switchover, and the migration itself can take as long as it needs.



    3. Database-Specific Differences



    Is there a difference in migration workflow between MongoDB vs PostgreSQL?



    They are hugely different. In MongoDB you don't need to run migrations at all unless you want to change the shape of existing documents. In Postgres, you have to run migrations if you want to change the shape of existing documents as well, but in addition, migrations are a required part of the workflow and are necessary every time you change a field or collection.



    Do both handle schema changes the same way, or are there DB-specific considerations?


    No, they handle schema changes very differently. MongoDB allows flexible, on-the-fly changes to document structure, whereas PostgreSQL enforces strict schemas.



    Any performance implications I should know about for either?



    The decision between which DB to use should be based on your schema—e.g. if you're using localization, arrays, blocks,

    hasMany

    Select fields MongoDB would be the better choice.



    See our database docs for more on this -->

    https://payloadcms.com/docs/database/overview#selecting-a-database

    3. Database-Specific Differences



    Is there a difference in migration workflow between MongoDB vs PostgreSQL?



    They are hugely different. In MongoDB you don't need to run migrations at all unless you want to change the shape of existing documents. In Postgres, you have to run migrations if you want to change the shape of existing documents as well, but in addition, migrations are a required part of the workflow and are necessary every time you change a field or collection.



    Do both handle schema changes the same way, or are there DB-specific considerations?


    No, they handle schema changes very differently. MongoDB allows flexible, on-the-fly changes to document structure, whereas PostgreSQL enforces strict schemas.



    Any performance implications I should know about for either?



    The decision between which DB to use should be based on your schema—e.g. if you're using localization, arrays, blocks, hasMany Select fields MongoDB would be the better choice.



    See our database docs for more on this -->

    https://payloadcms.com/docs/database/overview#selecting-a-database

    4. Safety Net Strategies



    What's your backup/rollback strategy before running migrations?



    Generally you want to leverage your DB provider backup functionality. Take a backup before running a significant migration and be ready to restore if something goes wrong.



    Do you use staging environments that mirror production data volume?


    I'd absolutely suggest a staging environment to mitigate performance issues or migration edge cases before deploying to production.



    Any tools or practices for "dry run" testing migrations?


    Database migrations in Payload use transactions, and they will either work or be automatically rolled back. So that gives you a layer of safety automatically, but for larger migrations using a staging database is the way to go.

  • default discord avatar
    sami_25411 months ago

    The same kinder issue. I’m running Payload v3.0 on Next.js with PostgreSQL and I’ve hit a migration snag when removing a collection that’s referenced by payload_locked_documents_rels. Here’s my setup and what happened:



    Environment:



    Payload v3.0,

    @967091941873426493

    /db-postgres


    Next.js 15.2.3, Node.js on Windows


    PostgreSQL local database payload_demo



    What I did locally (clean slate):



    # Reset local DB


    dropdb payload_demo


    createdb payload_demo



    # Bootstrap migrations


    npm run payload migrate:create initial-baseline --empty


    npm run payload migrate



    # Add

    Teams

    collection in payload.config.ts


    npm run dev # sees “➕ Created table

    teams

    ” → Ctrl+C


    npm run payload migrate:create add-teams


    npm run payload migrate # ✅ applies



    # Remove

    Teams

    from payload.config.ts


    npm run dev # sees “➖ Dropped table

    teams

    ” → Ctrl+C


    npm run payload migrate:create remove-teams


    npm run payload migrate




    The error:


    On npm run payload migrate for the remove-teams migration, I get:



    ERROR: Error running migration 20250613_121013_del_teams_database_schema


    constraint "payload_locked_documents_rels_team_fk" of relation "payload_locked_documents_rels" does not exist



    What’s the recommended way to handle auto-generated migrations for deleting collections when there are existing payload_locked_documents_rels FKs?



    Should I manually edit the migration to first check for the FK’s existence?



    Or is there a Payload config/flag that skips dropping these constraints?



    Any best practice to avoid “constraint … does not exist” errors when deleting collections?

Star on GitHub

Star

Chat on Discord

Discord

online

Can't find what you're looking for?

Get dedicated engineering support directly from the Payload team.