Skip to content

fix: return user_metadata in list/search responses#952

Open
oniani1 wants to merge 4 commits intosupabase:masterfrom
oniani1:fix/list-user-metadata
Open

fix: return user_metadata in list/search responses#952
oniani1 wants to merge 4 commits intosupabase:masterfrom
oniani1:fix/list-user-metadata

Conversation

@oniani1
Copy link
Copy Markdown
Contributor

@oniani1 oniani1 commented Mar 30, 2026

What kind of change does this PR introduce?

Bug fix - resolves #759

What is the current behavior?

storage.list() and list-v2 only return system metadata (size, mimetype, eTag) for each object. Custom user_metadata set during upload is omitted, forcing users to make N additional .info() calls to retrieve it.

What is the new behavior?

All list/search endpoints now include user_metadata in their response. Files return their stored user_metadata; folders return null.

Changes

SQL migration (0059-search-functions-user-metadata.sql):

  • Drops and recreates four search functions with user_metadata jsonb added to their RETURNS TABLE and SELECT queries:
    • storage.list_objects_with_delimiter (used by v2 name-sorted listing)
    • storage.search (used by v1 listing, both name and non-name sorting paths)
    • storage.search_v2 (router that delegates to the above)
    • storage.search_by_timestamp (used by v2 timestamp-sorted listing)
  • DROP FUNCTION IF EXISTS is required before each CREATE OR REPLACE because PostgreSQL cannot change a function's return type in-place
  • Folders emit NULL for user_metadata in all code paths

TypeScript (knex.ts):

  • Added 'user_metadata' to the select array in listObjectsV2 for the non-delimiter direct query path (line 383)

Test (object.test.ts):

  • Uploads a file with custom metadata, calls list, asserts user_metadata is present on files and null on folders

Verification

  • Ran all 59 migrations against a fresh PostgreSQL 15 instance
  • Confirmed all 4 functions return user_metadata via direct SQL queries
  • Tested all code paths: name sorting, timestamp sorting, non-name sorting, and direct delimiter listing

Additional context

  • The Obj schema and route handlers already supported user_metadata -- the data just never left the database layer
  • user_metadata column has existed on storage.objects since migration 0025
  • .info() correctly returns it; only the search/list functions were missing it
  • Backward compatible: normalizeColumns already strips user_metadata for tenants below migration 25, and migrations run sequentially so the column always exists before this migration
  • No S3 protocol changes needed -- S3 ListObjects spec doesn't include custom metadata

oniani1 added 2 commits March 30, 2026 23:08
Proves that storage.list() does not return user_metadata even
though the data exists on the objects table. See supabase#759.
All four search functions (list_objects_with_delimiter, search,
search_v2, search_by_timestamp) now include user_metadata in their
return types and queries. Folders return NULL for user_metadata.

Fixes supabase#759
@oniani1 oniani1 requested a review from a team as a code owner March 30, 2026 19:26
@oniani1 oniani1 force-pushed the fix/list-user-metadata branch 2 times, most recently from 34d186b to 880d4ac Compare March 30, 2026 19:47
PostgreSQL's CREATE OR REPLACE cannot change a function's return type.
Added DROP FUNCTION IF EXISTS before each CREATE OR REPLACE, matching
the pattern used in migration 0050.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

storage.list() does not return custom file metadata (only system fields)

1 participant