BSD-3-Clause licensed by John Goerzen
Maintained by Philippe
This version can be pinned in stack with:magic-2.0.0@sha256:0fd65090691300e5027317b1e6237be1adc8ebfe89b9c742c696cd6ea0d5d186,3912

Module documentation for 2.0.0

Used by 1 package in nightly-2026-07-15(full list with versions):

magic

It is a binding to the C libmagic library. It allows you to determine the type of a file not by looking at its name or extension, but rather by examining the contents itself.

libmagic can provide either a textual description or a MIME content type (and, occasionally, also a character set). The Haskell binding can examine files, open file descriptors, and in-memory data (as a strict ByteString). Results come back as Text.

Requirements

You need the C libmagic library and its development headers installed before building. It is part of the file package.

Platform Install
Debian / Ubuntu apt-get install libmagic-dev
Fedora dnf install file-devel
Arch pacman -S file
macOS (Homebrew) brew install libmagic
Nix file / file.dev

Building

With cabal:

cabal build
cabal test

With stack:

stack build
stack test

libmagic is located automatically via pkg-config. If pkg-config cannot find it (for example, an unusual install location), point Cabal at the library directly:

cabal build \
  --extra-lib-dirs=/path/to/lib \
  --extra-include-dirs=/path/to/include

Usage

Add magic to your build-depends. The easiest way in is Magic.FilePath, which takes ordinary String paths:

import Magic.FilePath          -- convenience facade: ordinary String paths
import qualified Data.Text.IO as T

main :: IO ()
main = do
  magic <- magicOpen MagicMimeType
  magicLoadDefault magic
  mime <- magicFile magic "some-file.png"
  T.putStrLn mime        -- e.g. "image/png"

Magic vs Magic.FilePath

import Magic is the primary API. It is the same in every way except that paths are OsPath instead of String. Prefer it when filename correctness matters.

Magic.FilePath is a drop-in facade that converts paths through the locale’s filesystem encoding (encodeFS / decodeFS). For ordinary ASCII/UTF-8 filenames under a UTF-8 locale that is perfectly fine. What you give up: a String path cannot faithfully represent every path the operating system can. Filenames containing bytes that are not valid in the current locale (raw non-UTF-8 bytes on Unix, names created under a different LANG/LC_*, and so on) may be corrupted or fail to round-trip, so you can fail to open a file that exists, or open the wrong one, and the outcome depends on the environment. OsPath stores the OS-native path bytes verbatim, so it represents any path losslessly and independently of the locale.

Author & history

magic-haskell was written by John Goerzen [email protected], who created it in 2005 and maintained it for nearly two decades. It is now maintained by Philippe, with development at https://github.com/philippedev101/magic-haskell.

License

3-clause BSD. See the COPYING file included with the package.

Changes

Changelog for magic

All notable changes to this project are documented here.

2.0.0 (2026-06-09)

A modernizing redesign, and the first release in which magic is genuinely safe and correct under real-world use. The reasons to upgrade:

  • Thread-safe handles. Magic is now an opaque handle whose operations are serialised by an internal per-handle lock, so sharing one handle across threads is safe (it was previously a silent data race). Use distinct handles for parallelism. (Magic was the transparent synonym type Magic = ForeignPtr CMagic, so the CMagic phantom type is no longer exported.)
  • Correct on any filename. Paths are now OsPath, which stores the OS-native path bytes verbatim and avoids the lossy locale round-trip that String paths suffer on unusual filenames. magicFile takes an OsPath; magicLoad, magicCompile, and magicCheck take [OsPath] (the empty list means the default database); magicGetPath returns [OsPath]. The new Magic.FilePath module offers the whole API with ordinary String paths for convenience.
  • Correct on any in-memory data. Removed magicString, which round-tripped data through the locale encoding and corrupted non-text bytes. Identify in-memory data with magicByteString (raw bytes) or magicCString (a raw pointer).
  • Memory-safe loading from memory. Restored magicLoadBuffers :: Magic -> [ByteString] -> IO () (removed in 1.1.2): the handle now retains the supplied buffers for its lifetime, so embedding and loading a compiled database from memory is memory-safe.
  • Typed, catchable errors. Failures raise a dedicated MagicException carrying the failing operation and libmagic’s message, with a readable displayException, instead of a generic IOError. (magicOpen still raises an errno IOError, as there is no handle yet to query.)
  • Correct, ergonomic flags. A MagicFlags bit-mask newtype replaces the old MagicFlag enumeration, whose Enum-as-bit-mask design mishandled aliased and composite constants. Combine flags with (<>), start from mempty, test with hasFlag, narrow with removeFlags; each flag is a pattern synonym, and show prints the set flags by name.
  • Text results. magicFile, magicStdin, magicCString, magicByteString, and magicDescriptor return Text.
  • Good-citizen instances. Added Generic and NFData for MagicFlags, MagicParam, and MagicException.

Migrating from 1.x

  • Results are Text: add Data.Text.unpack where you still need String.
  • In-memory data: magicString becomes magicByteString (pass a ByteString).
  • Flags: magicOpen [MagicMimeType, MagicError] becomes magicOpen (MagicMimeType <> MagicError), and [] becomes mempty.
  • Paths: adopt OsPath, or import Magic.FilePath to keep String paths.
  • Catch MagicException instead of IOException.

1.1.2 (2026-06-09)

Backwards-compatible additions: existing code continues to work unchanged. This release rounds out the binding to cover (almost) all of libmagic’s public API.

  • Added the remaining MagicFlag constructors from <magic.h>: MagicApple, MagicExtension, MagicCompressTransp, MagicNoCompressFork, MagicNodesc, and the whole no-check family (MagicNoCheckCompress, …Tar, …Soft, …Apptype, …Elf, …Text, …Cdf, …Csv, …Tokens, …Encoding, …Json, …Simh) plus MagicNoCheckBuiltin.
  • Added new operations in Magic.Operations: magicDescriptor (identify an open file descriptor), magicByteString (binary-safe identification of a strict ByteString), magicGetFlags, magicGetParam/magicSetParam with the new MagicParam type, magicCheck, magicGetPath, magicVersion, and magicErrno.
  • magicGetParam/magicSetParam require libmagic >= 5.21; magicGetFlags requires >= 5.05. All current systems are well past this.
  • New dependency: bytestring (a GHC boot library) for the ByteString entry points.
  • Moved the CMagic phantom type (the tag behind the Magic handle) into Magic.Types and removed the internal Magic.TypesLL module. CMagic is now documented and linkable from the exposed Magic.Types. Documentation polish throughout: full Haddock coverage with no warnings, @since annotations on the new API, and default values listed for each MagicParam.
  • magic_load is now imported as a safe foreign call (it was unsafe). It reads and parses the magic database from disk (blocking I/O), so under the threaded runtime loading a database no longer stalls other Haskell threads or blocks garbage collection. No API change.
  • Documented the thread-safety contract of the Magic handle: a single handle is not safe for concurrent use (serialise access or use one per thread); distinct handles are independent.

1.1.1 (2026-06-09)

No API changes: this release is a drop-in replacement for 1.1.

  • New maintainer: Philippe ([email protected]); package handed over from John Goerzen.
  • Modernised the Cabal package description (cabal-version: 2.4, proper library/test-suite stanzas, source-repository, tested-with).
  • Added an automatic pkgconfig flag: libmagic is now located via pkg-config when available, falling back transparently to plain extra-libraries linking otherwise.
  • Moved library sources under src/ and tests under test/ (no code or module-name changes).
  • Revived the original HUnit test suite in place: completed the unfinished Inittest module with real tests exercising the bindings against the system magic database, and fixed the runner to exit non-zero on failure.
  • Added a GitHub Actions CI workflow building and testing across GHC 9.6 / 9.8 / 9.10 / 9.12.
  • Removed dead imports so the library builds -Wall-clean.
  • Ships the unsafe-FFI fix (use safe FFI calls for blocking I/O) that was merged upstream after the 1.1 Hackage release but never published.

1.1 (2014-10) and earlier

Releases by John Goerzen. See the git history for details.