Question
I want to list the files and folders inside a single directory in Go without recursively visiting subdirectories.
I found filepath.Walk, but it automatically traverses into nested directories, which is not what I need.
What is the correct way to read just one directory level in Go?
// I do not want recursive traversal like this:
filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
return nil
})
Short Answer
By the end of this page, you will understand how to list the contents of a single directory in Go, when to use os.ReadDir instead of filepath.Walk, how to distinguish files from folders, and how this pattern is used in real applications.
Concept
In Go, there is an important difference between reading one directory and walking an entire directory tree.
- Reading one directory means: “Show me the entries directly inside this folder.”
- Walking a directory tree means: “Visit this folder and every nested folder inside it.”
If you only want the files and folders in one directory, filepath.Walk is usually the wrong tool because it is designed for recursive traversal.
For a single directory level, the right concept is to use directory-reading functions such as:
os.ReadDir(path)
This returns the entries directly inside the given directory. Each entry can represent:
- a file
- a directory
- a symbolic link
- another filesystem entry type
This matters because many programs need to inspect only one folder level, for example:
- showing uploaded files
- reading config files from a folder
- building a simple file browser
- scanning a log directory
Using the correct function makes your code:
- simpler
- faster to understand
- less error-prone
- more aligned with Go's standard library design
In modern Go, os.ReadDir is the usual choice for this task.
Mental Model
Think of a directory like a drawer in a filing cabinet.
os.ReadDir("myfolder")means: open this drawer and look at the items directly inside it.filepath.Walk("myfolder", ...)means: open this drawer, then open every folder inside it, then every folder inside those, and keep going.
If you only need to know what is in one drawer, you should not search the entire building.
That is why os.ReadDir is a better fit for listing a single directory.
Syntax and Examples
Basic syntax
entries, err := os.ReadDir(".")
if err != nil {
log.Fatal(err)
}
for _, entry := range entries {
fmt.Println(entry.Name())
}
Example: list files and folders in one directory
package main
import (
"fmt"
"log"
"os"
)
func main() {
entries, err := os.ReadDir(".")
if err != nil {
log.Fatal(err)
}
for _, entry := range entries {
if entry.IsDir() {
fmt.Println("DIR :", entry.Name())
} else {
fmt.Println("FILE:", entry.Name())
}
}
}
What this does
os.ReadDir(".")reads the current directory.- It returns a slice of directory entries.
entry.Name()gives the name of each item.entry.IsDir()tells you whether that item is a directory.
Example: read a specific folder
Step by Step Execution
Consider this program:
package main
import (
"fmt"
"log"
"os"
)
func main() {
entries, err := os.ReadDir(".")
if err != nil {
log.Fatal(err)
}
for _, entry := range entries {
fmt.Println(entry.Name(), entry.IsDir())
}
}
Step by step
os.ReadDir(".")asks the operating system to read the current directory.- Go returns two values:
entries: a list of items in that directoryerr: an error if something went wrong
- The
if err != nilcheck stops the program if the directory cannot be read. - The
for _, entry := range entriesloop processes each item one by one. entry.Name()prints the item's name.entry.IsDir()printstrueif the item is a directory, otherwisefalse.
Real World Use Cases
Listing a single directory is common in everyday Go programs.
Examples
- Upload processing: read files waiting in an upload folder
- Config loading: list config files in a
configs/directory - Static site tools: inspect templates or assets in one folder
- Log management: list log files before archiving or deleting them
- CLI utilities: build commands like a simplified
ls - Backup tools: inspect top-level folders before deeper processing
Example: process only .json files in one folder
entries, err := os.ReadDir("configs")
if err != nil {
log.Fatal(err)
}
for _, entry := range entries {
if entry.IsDir() {
continue
}
name := entry.Name()
if filepath.Ext(name) == ".json" {
fmt.Println("config file:", name)
}
}
This is useful when you want to work with only the immediate contents of a folder and ignore nested directories.
Real Codebase Usage
In real projects, developers rarely just print file names. They usually combine directory listing with filtering, validation, and error handling.
Common patterns
Guard clause for read errors
entries, err := os.ReadDir(dir)
if err != nil {
return err
}
This keeps the rest of the function clean.
Skip directories early
for _, entry := range entries {
if entry.IsDir() {
continue
}
// process file
}
This is an example of an early-continue pattern.
Filter by extension
for _, entry := range entries {
if entry.IsDir() {
continue
}
if filepath.Ext(entry.Name()) != ".txt" {
continue
}
// handle .txt file
}
Build full paths safely
When you need to open a file, combine the directory path and entry name with filepath.Join:
fullPath := filepath.Join(dir, entry.Name())
Common Mistakes
1. Using filepath.Walk when recursion is not needed
Broken approach for this use case:
filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
fmt.Println(path)
return nil
})
Why it is a problem:
- it visits subdirectories too
- it does more work than needed
- it makes simple code more complex
Use os.ReadDir instead.
2. Forgetting to handle errors
Broken code:
entries, _ := os.ReadDir("missing-folder")
for _, entry := range entries {
fmt.Println(entry.Name())
}
Why this is bad:
- if the directory does not exist, the failure is silently ignored
- debugging becomes harder
Better:
entries, err := os.ReadDir("missing-folder")
if err != nil {
log.Fatal(err)
}
3. Assuming names are full paths
Comparisons
| Task | Best choice | Why |
|---|---|---|
| List one directory level | os.ReadDir | Simple and direct |
| Walk all nested directories | filepath.Walk or filepath.WalkDir | Designed for recursion |
| Check whether a path exists and get metadata | os.Stat | Returns file info for one path |
| Open and read file contents | os.Open | Used for reading file data |
os.ReadDir vs filepath.Walk
| Feature |
|---|
Cheat Sheet
entries, err := os.ReadDir(dir)
if err != nil {
return err
}
for _, entry := range entries {
name := entry.Name()
isDir := entry.IsDir()
_ = name
_ = isDir
}
Quick rules
- Use
os.ReadDir(path)to list one directory level. - Use
filepath.Walkorfilepath.WalkDirfor recursive traversal. entry.Name()gives the entry name, not the full path.- Use
filepath.Join(dir, entry.Name())to build full paths. - Use
entry.IsDir()to check whether an item is a directory. - Use
entry.Info()only when you need extra metadata.
Common pattern
entries, err := os.ReadDir(dir)
if err != nil {
return err
}
for _, entry := range entries {
if entry.IsDir() {
continue
}
fullPath := filepath.Join(dir, entry.Name())
fmt.Println(fullPath)
}
Edge cases
- The directory may not exist.
FAQ
How do I list files in a directory in Go?
Use os.ReadDir(path), then loop over the returned entries.
How do I avoid recursion when listing directories in Go?
Do not use filepath.Walk for this. Use os.ReadDir, which reads only one directory level.
How can I tell whether an entry is a file or folder in Go?
Use entry.IsDir(). If it returns true, the entry is a directory.
How do I get the full path of a listed file?
Use filepath.Join(dir, entry.Name()).
Should I use ioutil.ReadDir or os.ReadDir?
Use os.ReadDir in modern Go code.
How do I get file size when listing a directory?
Call entry.Info() and then use info.Size().
Does os.ReadDir include subdirectories' contents?
No. It lists only the entries directly inside the given directory.
Mini Project
Description
Build a small Go program that lists the contents of a chosen directory and labels each entry as either a file or a folder. This demonstrates how to read one directory level, handle errors, and work with directory entries in a practical way.
Goal
Create a command-line program that prints all items in a directory and clearly identifies whether each item is a file or directory.
Requirements
- Read a directory path from a variable or command-line argument.
- Use
os.ReadDirto load the directory contents. - Print each entry name with either
FILEorDIR. - Handle errors if the directory cannot be read.
Keep learning
Related questions
Blank Identifier Imports in Go: What `_` Means in an Import Statement
Learn what `_` means in a Go import, why blank identifier imports run package init code, and when to use them safely.
Check if a Value Exists in a Slice in Go
Learn how to check whether a value exists in a slice in Go, and why Go has no Python-style `in` operator for arrays or slices.
Concatenating Slices in Go with append
Learn how to concatenate two slices in Go using append and the ... operator, with examples, pitfalls, and practical usage.