Skip to content

column "prefix" does not exist in media collection when using @payloadcms/storage-s3 with prefix option and Postgres migrations #12475

@SebastianSchuetze

Description

@SebastianSchuetze

Describe the Bug

When using the @payloadcms/storage-s3 plugin with a prefix configured for a media collection (e.g., media), and deploying to an environment that uses database migrations (like Vercel with Supabase/Postgres, or a local production-like setup), a runtime error column "prefix" does not exist occurs. This error typically happens during operations on the media collection, such as seeding (specifically when attempting to delete existing media).

The issue seems to stem from a discrepancy:

The prefix option in the s3Storage plugin configuration (e.g., collections: { media: { prefix: 'media' } }) leads to the generated payload-types.ts including prefix?: string | null; as an optional field in the Media interface.

However, the database migration files generated by PayloadCMS do not include a prefix column in the media table schema.
When PayloadCMS performs database operations, it appears to rely on the payload-types.ts definition, causing the ORM (db-postgres with Drizzle) to query for a prefix column that doesn't exist in the database schema when migrations are the source of truth.
This bug does not manifest in local development environments when NODE_ENV=development if payload db:push is used, likely because db:push synchronizes the schema (potentially creating the prefix column) based on the (plugin-influenced) payload-types.ts or derived config. However, the error surfaces when NODE_ENV=production or when relying strictly on migrations, as the prefix column is not part of the formal migration-defined schema.

Expected Behavior:
The prefix configuration within the S3 storage plugin should be used solely for determining the storage path in the S3 bucket. It should not:

  1. Cause a prefix field to be added to the Media collection's type definition in payload-types.ts unless explicitly defined as a custom field by the user in their collection config.
  2. Lead to the ORM attempting to query a prefix column in the database if that column is not defined in the migrations.

Link to the code that reproduces this issue

https://github.com/findmydoc-platform/website/blob/dc267ba0e7b937f558eef72c6cffa969dc459df3/src/plugins/index.ts#L113

Reproduction Steps

  1. Configure a new PayloadCMS project with @payloadcms/db-postgres and @payloadcms/storage-s3.
  2. Define a media collection similar to the one in src/collections/Media.ts (without a prefix field).
  3. In payload.config.ts, add the @payloadcms/storage-s3 plugin and configure a prefix for the media collection (e.g., prefix: 'media').
  4. Generate types: pnpm run payload generate:types. Observe that payload-types.ts now includes prefix?: string | null; in the Media interface.
  5. Create an initial migration: pnpm run payload migrate:create initial_schema. Inspect the migration SQL; it will not contain a prefix column for the media table.
  6. Run the migration against a clean Postgres database: pnpm run payload migrate.
  7. Set NODE_ENV=production.
  8. Attempt to seed the database or perform operations that involve querying or deleting from the media collection (e.g., using a seed script that clears collections, like the one in your src/endpoints/seed/index.ts which calls payload.db.deleteMany({ collection: 'media', ... })).
  9. Observe the error: ERROR (payload): column "prefix" does not exist.

Which area(s) are affected? (Select all that apply)

plugin: other, db-postgres

Environment Info

Binaries:
  Node: 23.10.0
  npm: 10.9.2
  Yarn: N/A
  pnpm: 10.10.0
Relevant Packages:
  payload: 3.38.0
  next: 15.3.2
  @payloadcms/db-postgres: 3.38.0
  @payloadcms/email-nodemailer: 3.38.0
  @payloadcms/graphql: 3.38.0
  @payloadcms/live-preview: 3.38.0
  @payloadcms/live-preview-react: 3.38.0
  @payloadcms/next/utilities: 3.38.0
  @payloadcms/payload-cloud: 3.38.0
  @payloadcms/plugin-cloud-storage: 3.38.0
  @payloadcms/plugin-form-builder: 3.38.0
  @payloadcms/plugin-nested-docs: 3.38.0
  @payloadcms/plugin-redirects: 3.38.0
  @payloadcms/plugin-search: 3.38.0
  @payloadcms/plugin-seo: 3.38.0
  @payloadcms/richtext-lexical: 3.38.0
  @payloadcms/storage-s3: 3.38.0
  @payloadcms/translations: 3.38.0
  @payloadcms/ui/shared: 3.38.0
  react: 19.1.0
  react-dom: 19.1.0
Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 24.5.0: Tue Apr 22 19:54:49 PDT 2025; root:xnu-11417.121.6~2/RELEASE_ARM64_T6000
  Available memory (MB): 32768
  Available CPU cores: 8

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions