FilePath Hackage version

The filepath package provides functionality for manipulating FilePath values, and is shipped with GHC. It provides two variants for filepaths:

  1. legacy filepaths: type FilePath = String
  2. operating system abstracted filepaths (OsPath): internally unpinned ShortByteString (platform-dependent encoding)

It is recommended to use OsPath when possible, because it is more correct.

For each variant there are three main modules:

  • System.FilePath.Posix / System.OsPath.Posix manipulates POSIX/Linux style FilePath values (with / as the path separator).
  • System.FilePath.Windows / System.OsPath.Windows manipulates Windows style FilePath values (with either \ or / as the path separator, and deals with drives).
  • System.FilePath / System.OsPath for dealing with current platform-specific filepaths

All three modules provide the same API, and the same documentation (calling out differences in the different variants).

System.OsString is like System.OsPath, but more general purpose. Refer to the documentation of those modules for more information.

What is a FilePath?

In Haskell, the legacy definition (used in base and Prelude) is type FilePath = String, where a Haskell String is a list of Unicode code points.

The new definition is (simplified) newtype OsPath = AFP ShortByteString, where ShortByteString is an unpinned byte array and follows syscall conventions, preserving the encoding.

On unix, filenames don’t have a predefined encoding as per the POSIX specification and are passed as char[] to syscalls.

On windows (at least the API used by Win32) filepaths are UTF-16LE strings.

You are encouraged to use OsPath whenever possible, because it is more correct.

Also note that this is a low-level library and it makes no attempt at providing a more type safe variant for filepaths (e.g. by distinguishing between absolute and relative paths) and ensures no invariants (such as filepath validity).

For such libraries, check out the following:


Changelog for filepath package

Note: below all FilePath values are unquoted, so \\ really means two backslashes. Dec 2023

  • Improve deprecation warnings wrt #209 Nov 2023

  • deprecate OsString modules Jul 2023

  • Fix isInfixOf and breakSubString in Word16, wrt #195 Feb 2023

  • Fix a regression in splitFileName wrt #189 Feb 2023

  • Speed up splitFileName, splitExtension, readDriveLetter and various other helpers (up to 20x faster) by @Bodigrim Feb 2023

  • Fix regression in System.FilePath.Windows.normalise wrt #187
  • Fix tests on GHC 9.4.4
  • Avoid head and tail July 2022

Implementation of the Abstract FilePath Proposal in user-space as a separate type.

Introduction to the new API is explained in this blog post. Dec 2021

This release is purely a documentation release, fixing the broken haddock links.

Affected users

This release affects users who apply downstream patches to System.FilePath.Internal, since System.FilePath.Posix and System.FilePath.Windows are now generated via make cpp during development.

To make your patch apply, either apply it to System.FilePath.Posix and System.FilePath.Windows instead or run make cpp after applying your patch.


  • Document relation between joinPath and (</>) wrt #82, #82
  • Clarify that normalise does not remove .. wrt #86
  • Make clear that equalFilePath does not expand .. wrt #87
  • Fix haddock source links by manually cpping wrt #81
  • Make export list in System.FilePath explicit to get haddocks on the landing module Jul 2018

  • Bundled with GHC 8.6.1

1.4.2 Jan 2018

  • Bundled with GHC 8.4.1

  • Add isExtensionOf function. Feb 2017

  • Bundled with GHC 8.2.1 Nov 2016

  • Bundled with GHC 8.0.2

  • Documentation improvements Dec 2015

  • Bundled with GHC 8.0.1

  • Add replaceExtensions and stripExtension functions.

  • Make isValid detect more invalid Windows paths, e.g. nul .txt and foo\nbar.

  • Improve the documentation.

  • Bug fix: isValid "\0" now returns False, instead of True Mar 2015

  • Bundled with GHC 7.10.1

  • New function: Add -<.> as an alias for replaceExtension.

  • Semantic change: joinDrive /foo bar now returns /foo/bar, instead of /foobar

  • Semantic change: on Windows, splitSearchPath File1;\"File 2\" now returns [File1,File2] instead of [File1,\"File2\"]

  • Bug fix: on Posix systems, normalise //home now returns /home, instead of //home

  • Bug fix: normalise /./ now returns / on Posix and \ on Windows, instead of // and \\

  • Bug fix: isDrive "" now returns False, instead of True

  • Bug fix: on Windows, dropTrailingPathSeparator / now returns / unchanged, instead of the normalised \

  • Bug fix: on Windows, equalFilePath C:\ C: now returns False, instead of True

  • Bug fix: on Windows, isValid \\\foo now returns False, instead of True

  • Bug fix: on Windows, isValid \\?\D:file now returns False, instead of True

  • Bug fix: on Windows, normalise \ now returns \ unchanged, instead of \\

  • Bug fix: on Windows, normalise C:.\ now returns C:, instead of C:\\

  • Bug fix: on Windows, normalise //server/test now returns \\server\test, instead of //server/test unchanged

  • Bug fix: on Windows, makeRelative / // now returns //, instead of "" Mar 2014

  • Bundled with GHC 7.8.1

  • Update to Cabal 1.10 format

  • Minor Haddock cleanups Sep 2012

  • Bundled with GHC 7.6.1

  • No changes Feb 2012

  • Bundled with GHC 7.4.1

  • Add support for SafeHaskell

  • Bug fix: normalise / now returns /, instead of /.