Skip to main content
RapidDev - Software Development Agency
supabase-tutorial

How to List Files in a Supabase Storage Bucket

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.

What you'll learn

  • How to list files and folders in a Supabase Storage bucket using the JS client
  • How to paginate and sort file listings for large buckets
  • How to filter files by folder prefix and search by filename
  • How RLS policies affect which files are returned in list results
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate7 min read10-15 minSupabase (all plans), @supabase/supabase-js v2+March 2026RapidDev Engineering Team
TL;DR

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

1

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.

typescript
1import { createClient } from '@supabase/supabase-js'
2
3const supabase = createClient(
4 process.env.NEXT_PUBLIC_SUPABASE_URL!,
5 process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
6)
7
8const { data, error } = await supabase.storage
9 .from('documents')
10 .list()
11
12if (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.

2

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.

typescript
1// List files in the 'invoices/2024' folder
2const { data, error } = await supabase.storage
3 .from('documents')
4 .list('invoices/2024')
5
6// List files in a user-specific folder
7const userId = 'abc-123-def'
8const { data: userFiles, error: userError } = await supabase.storage
9 .from('documents')
10 .list(userId)

Expected result: Files and subfolders within the specified path are returned.

3

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.

typescript
1const PAGE_SIZE = 20
2let currentPage = 0
3
4async function loadPage(page: number) {
5 const { data, error } = await supabase.storage
6 .from('documents')
7 .list('uploads', {
8 limit: PAGE_SIZE,
9 offset: page * PAGE_SIZE,
10 })
11
12 if (error) {
13 console.error('Pagination error:', error.message)
14 return []
15 }
16 return data
17}
18
19// Load first page
20const firstPage = await loadPage(0)
21// Load second page
22const secondPage = await loadPage(1)

Expected result: Files are returned in pages of the specified size, with offset controlling which page is loaded.

4

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.

typescript
1// Sort by name ascending (alphabetical)
2const { data: byName } = await supabase.storage
3 .from('documents')
4 .list('uploads', {
5 sortBy: { column: 'name', order: 'asc' },
6 })
7
8// Sort by creation date, newest first
9const { data: byDate } = await supabase.storage
10 .from('documents')
11 .list('uploads', {
12 sortBy: { column: 'created_at', order: 'desc' },
13 })

Expected result: Files are returned in the specified sort order.

5

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.

typescript
1// Search for files starting with 'report'
2const { data, error } = await supabase.storage
3 .from('documents')
4 .list('uploads', {
5 search: 'report',
6 })
7
8console.log(`Found ${data?.length} files matching 'report'`)

Expected result: Only files whose names start with the search string are returned.

Complete working example

storage-file-browser.ts
1import { createClient } from '@supabase/supabase-js'
2
3const supabase = createClient(
4 process.env.NEXT_PUBLIC_SUPABASE_URL!,
5 process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
6)
7
8interface ListOptions {
9 folder?: string
10 page?: number
11 pageSize?: number
12 sortBy?: 'name' | 'created_at' | 'updated_at'
13 sortOrder?: 'asc' | 'desc'
14 search?: string
15}
16
17async 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 } = options
26
27 const { data, error } = await supabase.storage
28 .from(bucket)
29 .list(folder, {
30 limit: pageSize,
31 offset: page * pageSize,
32 sortBy: { column: sortBy, order: sortOrder },
33 ...(search ? { search } : {}),
34 })
35
36 if (error) {
37 console.error('List files error:', error.message)
38 return { files: [], folders: [], hasMore: false }
39 }
40
41 const files = data.filter((item) => item.id !== null)
42 const folders = data.filter((item) => item.id === null)
43 const hasMore = data.length === pageSize
44
45 return { files, folders, hasMore }
46}
47
48// === Usage examples ===
49
50// List root of bucket
51const root = await listFiles('documents')
52console.log('Root folders:', root.folders.map((f) => f.name))
53console.log('Root files:', root.files.map((f) => f.name))
54
55// List a subfolder with pagination
56const 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.

ChatGPT Prompt

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.

Supabase Prompt

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.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.