To list files in a Supabase Storage bucket, use storage.from('bucket-name').list() which returns an array of file and folder objects. You can filter by folder prefix, paginate with limit and offset, sort by name or creation date, and search for specific filenames. The list method respects RLS policies on storage.objects, so users only see files they have SELECT access to.
Listing and Browsing Files in Supabase Storage Buckets
Supabase Storage organizes files using path prefixes that act as virtual folders. The list() method lets you browse files within a bucket, filter by folder, paginate results, and sort by different criteria. This tutorial shows you how to build a file browser that handles folders, pagination, and search within Supabase Storage.
Prerequisites
- A Supabase project with a storage bucket containing files
- The Supabase JS client installed (@supabase/supabase-js v2+)
- RLS policies on storage.objects granting SELECT access
- Basic understanding of async/await in JavaScript
Step-by-step guide
List all files in the root of a bucket
List all files in the root of a bucket
Use storage.from('bucket-name').list() to retrieve files at the root level of a bucket. The method returns an array of FileObject items, each containing the file name, id, created_at, updated_at, and metadata. Folders appear as objects with a null id. By default, list() returns up to 100 items from the root level. Files nested in subfolders are not included in root-level listings — you must specify the folder path to list nested files.
1import { createClient } from '@supabase/supabase-js'23const supabase = createClient(4 process.env.NEXT_PUBLIC_SUPABASE_URL!,5 process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!6)78const { data, error } = await supabase.storage9 .from('documents')10 .list()1112if (error) {13 console.error('List error:', error.message)14} else {15 data.forEach((item) => {16 console.log(item.name, item.id ? 'file' : 'folder')17 })18}Expected result: An array of file and folder objects at the root level of the bucket is returned.
List files inside a specific folder
List files inside a specific folder
Pass the folder path as the first argument to list() to browse files within that folder. The path should not start or end with a slash. For nested folders, use forward slashes to separate path segments. The returned items are relative to the specified folder, so you only see the immediate children — not deeply nested files.
1// List files in the 'invoices/2024' folder2const { data, error } = await supabase.storage3 .from('documents')4 .list('invoices/2024')56// List files in a user-specific folder7const userId = 'abc-123-def'8const { data: userFiles, error: userError } = await supabase.storage9 .from('documents')10 .list(userId)Expected result: Files and subfolders within the specified path are returned.
Paginate results with limit and offset
Paginate results with limit and offset
For buckets with many files, use the limit and offset options to paginate results. The limit option sets the maximum number of items returned (default 100), and offset skips that many items from the beginning. Combine these to build a paginated file browser UI. Note that offset-based pagination can miss files if items are added or removed between pages.
1const PAGE_SIZE = 202let currentPage = 034async function loadPage(page: number) {5 const { data, error } = await supabase.storage6 .from('documents')7 .list('uploads', {8 limit: PAGE_SIZE,9 offset: page * PAGE_SIZE,10 })1112 if (error) {13 console.error('Pagination error:', error.message)14 return []15 }16 return data17}1819// Load first page20const firstPage = await loadPage(0)21// Load second page22const secondPage = await loadPage(1)Expected result: Files are returned in pages of the specified size, with offset controlling which page is loaded.
Sort file listings by column
Sort file listings by column
Use the sortBy option to control the order of returned files. You can sort by 'name', 'created_at', or 'updated_at'. The order can be 'asc' (ascending) or 'desc' (descending). Sorting by created_at in descending order is useful for showing the most recently uploaded files first.
1// Sort by name ascending (alphabetical)2const { data: byName } = await supabase.storage3 .from('documents')4 .list('uploads', {5 sortBy: { column: 'name', order: 'asc' },6 })78// Sort by creation date, newest first9const { data: byDate } = await supabase.storage10 .from('documents')11 .list('uploads', {12 sortBy: { column: 'created_at', order: 'desc' },13 })Expected result: Files are returned in the specified sort order.
Search for files by name
Search for files by name
Use the search option to filter files by name. The search matches files whose name starts with the given string (prefix match). This is useful for implementing a search bar in your file browser. The search is case-sensitive and only matches file names, not folder paths.
1// Search for files starting with 'report'2const { data, error } = await supabase.storage3 .from('documents')4 .list('uploads', {5 search: 'report',6 })78console.log(`Found ${data?.length} files matching 'report'`)Expected result: Only files whose names start with the search string are returned.
Complete working example
1import { createClient } from '@supabase/supabase-js'23const supabase = createClient(4 process.env.NEXT_PUBLIC_SUPABASE_URL!,5 process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!6)78interface ListOptions {9 folder?: string10 page?: number11 pageSize?: number12 sortBy?: 'name' | 'created_at' | 'updated_at'13 sortOrder?: 'asc' | 'desc'14 search?: string15}1617async function listFiles(bucket: string, options: ListOptions = {}) {18 const {19 folder = '',20 page = 0,21 pageSize = 20,22 sortBy = 'name',23 sortOrder = 'asc',24 search,25 } = options2627 const { data, error } = await supabase.storage28 .from(bucket)29 .list(folder, {30 limit: pageSize,31 offset: page * pageSize,32 sortBy: { column: sortBy, order: sortOrder },33 ...(search ? { search } : {}),34 })3536 if (error) {37 console.error('List files error:', error.message)38 return { files: [], folders: [], hasMore: false }39 }4041 const files = data.filter((item) => item.id !== null)42 const folders = data.filter((item) => item.id === null)43 const hasMore = data.length === pageSize4445 return { files, folders, hasMore }46}4748// === Usage examples ===4950// List root of bucket51const root = await listFiles('documents')52console.log('Root folders:', root.folders.map((f) => f.name))53console.log('Root files:', root.files.map((f) => f.name))5455// List a subfolder with pagination56const page1 = await listFiles('documents', {57 folder: 'invoices/2024',58 page: 0,59 pageSize: 10,60 sortBy: 'created_at',61 sortOrder: 'desc',62})63console.log('Page 1 files:', page1.files.map((f) => f.name))64console.log('Has more:', page1.hasMore)Common mistakes when listting Files in a Supabase Storage Bucket
Why it's a problem: Adding a leading or trailing slash to the folder path
How to avoid: The folder path should not start or end with a slash. Use 'invoices/2024' not '/invoices/2024/' — leading and trailing slashes cause the list to return empty results.
Why it's a problem: Expecting deeply nested files to appear when listing a parent folder
How to avoid: The list() method only returns immediate children of the specified folder. To see nested files, call list() again with the subfolder path.
Why it's a problem: Forgetting that RLS policies affect list results
How to avoid: If your list returns empty but files exist, check that you have a SELECT policy on storage.objects for the authenticated role. Without a SELECT policy, RLS blocks all reads.
Why it's a problem: Using search as a substring match when it is actually a prefix match
How to avoid: The search option matches file names that start with the given string. For substring matching, fetch all files and filter client-side with JavaScript's includes() method.
Best practices
- Always paginate listings with limit and offset for buckets with many files
- Separate files from folders in the response by checking whether the id field is null
- Use the user-scoped folder pattern to list only files belonging to the authenticated user
- Cache file listings on the client and invalidate when files are uploaded or deleted
- Combine sorting with pagination for a consistent file browser experience
- Handle empty results gracefully — display a helpful message instead of a blank page
- Set appropriate RLS SELECT policies on storage.objects before listing files
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I have a Supabase Storage bucket called 'uploads' with files organized in user-specific folders. Show me how to list files in a user's folder with pagination (20 per page), sorted by creation date, using the @supabase/supabase-js v2 client.
Build a reusable file listing function for Supabase Storage that supports folder browsing, pagination with limit and offset, sorting by name or date, and prefix-based search. Return files and folders separately.
Frequently asked questions
What is the maximum number of files returned by list()?
The default limit is 100 files per call. You can increase this up to 1000 by setting the limit option. For larger listings, use pagination with offset to load files in batches.
How do I know if a returned item is a folder or a file?
Folders have a null id field and files have a non-null id. Check item.id === null to identify folders in the listing results.
Can I list files across multiple folders in one call?
No, each list() call retrieves files from a single folder path. To list files across multiple folders, make separate list() calls for each folder and merge the results.
Why does my file listing return empty even though files exist?
This is almost always an RLS issue. Check that you have a SELECT policy on storage.objects for the authenticated role. Also verify the folder path is correct — no leading or trailing slashes.
Does the search option support regular expressions?
No, the search option only supports prefix matching. It returns files whose names start with the given string. For more complex search patterns, fetch results and filter them client-side.
Can I list files in a bucket without authentication?
Only if the bucket is public and you have a SELECT policy for the anon role on storage.objects. For private buckets, the user must be authenticated and have a matching SELECT policy.
Can RapidDev help build a file management system with Supabase Storage?
Yes, RapidDev can design and implement a complete file management system using Supabase Storage, including folder structures, pagination, search, and user-scoped access controls.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation