Skip to main content
The filepath package provides functions to parse and construct file paths in a way that is portable across operating systems. It handles differences like dir/file on Linux vs. dir\file on Windows automatically.

Why Use filepath?

The filepath package ensures your code works correctly across different operating systems by handling platform-specific path separators and conventions.

Joining Paths

Use filepath.Join to construct paths portably:
package main

import (
	"fmt"
	"path/filepath"
)

func main() {
	// Join path components
	p := filepath.Join("dir1", "dir2", "filename")
	fmt.Println("p:", p)
	// Output on Linux: dir1/dir2/filename
	// Output on Windows: dir1\dir2\filename
}
Never concatenate paths manually with / or \. Always use filepath.Join for portability.

Path Normalization

filepath.Join also normalizes paths by removing superfluous separators and directory changes:
// Removes extra separators
fmt.Println(filepath.Join("dir1//", "filename"))
// Output: dir1/filename

// Resolves parent directory references
fmt.Println(filepath.Join("dir1/../dir1", "filename"))
// Output: dir1/filename
filepath.Join automatically cleans paths, removing redundant separators and resolving . and .. references.

Splitting Paths

Directory and Base

p := filepath.Join("dir1", "dir2", "filename")

// Get directory portion
fmt.Println("Dir(p):", filepath.Dir(p))
// Output: dir1/dir2

// Get base filename
fmt.Println("Base(p):", filepath.Base(p))
// Output: filename

Split in One Call

dir, file := filepath.Split(p)
fmt.Printf("dir: %s, file: %s\n", dir, file)

filepath.Dir

Returns the directory portion of a path

filepath.Base

Returns the last element of a path (filename)

Checking Path Types

Absolute vs Relative

// Check if path is absolute
fmt.Println(filepath.IsAbs("dir/file"))
// Output: false

fmt.Println(filepath.IsAbs("/dir/file"))
// Output: true (on Unix)

fmt.Println(filepath.IsAbs("C:\\dir\\file"))
// Output: true (on Windows)
What constitutes an absolute path varies by operating system. filepath.IsAbs handles these differences automatically.

Working with Extensions

Extracting Extensions

filename := "config.json"

// Get extension
ext := filepath.Ext(filename)
fmt.Println(ext)
// Output: .json

Removing Extensions

import "strings"

// Remove extension to get base name
name := strings.TrimSuffix(filename, ext)
fmt.Println(name)
// Output: config
filepath.Ext returns the extension including the dot (.json), or an empty string if there is no extension.

Relative Paths

Find a relative path between a base and target:
// Find relative path from base to target
rel, err := filepath.Rel("a/b", "a/b/t/file")
if err != nil {
	panic(err)
}
fmt.Println(rel)
// Output: t/file

// Relative path between different branches
rel, err = filepath.Rel("a/b", "a/c/t/file")
if err != nil {
	panic(err)
}
fmt.Println(rel)
// Output: ../c/t/file
filepath.Rel returns an error if the target cannot be made relative to the base (e.g., on different drives on Windows).

Complete Example

package main

import (
	"fmt"
	"path/filepath"
	"strings"
)

func main() {
	// Joining paths
	p := filepath.Join("dir1", "dir2", "filename")
	fmt.Println("p:", p)

	// Path normalization
	fmt.Println(filepath.Join("dir1//", "filename"))
	fmt.Println(filepath.Join("dir1/../dir1", "filename"))

	// Splitting paths
	fmt.Println("Dir(p):", filepath.Dir(p))
	fmt.Println("Base(p):", filepath.Base(p))

	// Checking absolute paths
	fmt.Println(filepath.IsAbs("dir/file"))
	fmt.Println(filepath.IsAbs("/dir/file"))

	// Working with extensions
	filename := "config.json"
	ext := filepath.Ext(filename)
	fmt.Println(ext)
	fmt.Println(strings.TrimSuffix(filename, ext))

	// Relative paths
	rel, err := filepath.Rel("a/b", "a/b/t/file")
	if err != nil {
		panic(err)
	}
	fmt.Println(rel)

	rel, err = filepath.Rel("a/b", "a/c/t/file")
	if err != nil {
		panic(err)
	}
	fmt.Println(rel)
}

Common Operations

path := filepath.Join("home", "user", "documents", "file.txt")

Best Practices

Never manually concatenate path components with / or \. Use filepath.Join to ensure cross-platform compatibility.
The path package is for URL paths. For filesystem paths, always use path/filepath.
filepath.Rel can return errors when paths are on different volumes or drives. Always check the error return value.
Use filepath.Clean to normalize user-provided paths before processing:
cleanPath := filepath.Clean(userInput)
Don’t assume / or \ as separators. Use filepath.Separator or os.PathSeparator if needed.
When needed, convert relative paths to absolute using filepath.Abs:
absPath, err := filepath.Abs("relative/path")

Additional Functions

filepath.Clean

Returns the shortest path equivalent to path by removing . and .. elements

filepath.Abs

Returns an absolute representation of path

filepath.Match

Reports whether name matches the shell pattern

filepath.Glob

Returns names of all files matching pattern

Directories

Learn how to work with directories

Reading Files

Learn how to read files in Go

Build docs developers (and LLMs) love