The OPAM manual

This manual gathers reference information on OPAM and its file formats. It is primarily of use for packagers, package maintainers and repository maintainers.

  • For simple usage of OPAM, see the Usage page, and the comprehensive built-in documentation opam [command] --help.
  • For a gentler introduction to packaging, see the Packaging guide
  • For a more complete specification, and if you are interested in more details on the layout of ~/.opam, you may want to check the OPAM Developer's Manual

This version of the manual documents the version 1.2 of the file formats, with some 1.2.1 experimental extensions mentionned.

General file format

General syntax

The OPAM file formats share a common base syntax. The files are utf8 encoded and made of a list of fields in the form <field-name>: <value>.

Available field names are specific to each specific file format, and each of them only allows values of a certain format.

Base values can be literal booleans, integers or strings, identifiers, and operators. Strings allow the escapes \\, \n, \r, \b, \t, as well as three-digit decimal and two-digit hexadecimal character codes (\NNN and \xNN), and escaped newlines. Lists must be enclosed in square brackets unless they contain a single element. Values can be followed by an argument in braces. Parentheses may be used to group sub-expressions.

type format example
bool true|false true
int -?[0-9]+ 42
string "..." "a string"
ident [a-zA-Z_][a-zA-Z0-9:_+-]* foo
operator [!=<>|&+:]+ >=
list <value> or [ <value> <value> ... ] [ foo "bar" ]
option <value> or <value> { <value> <value> ... } foo { > "0" }
parens (<value>) (foo & bar)

Comments may be either enclosed in (* and *), or # and newline. They are ignored by OPAM.

Package Formulas

Both package names and versions are encoded as strings. Formulas allow to specify conditions on installed packages. They are logic formulas using the operators & and | for AND and OR, over package names:

("neat_package" | "also_neat_package") & "required_package"

Package names can be suffixed with version constraints, which restricts the requirement further. Version constraints have the form <relop> <version> and can be combined with binary AND & and OR |, and prefix NOT !. The allowed relational operators are =, !=, <, <=, > and >=, and their meaning is defined by Version Ordering.

Version Ordering follows the basics of the Debian definition.

It is basically "lexicographical order, with numbers handled properly". In more detail (see the Debian page for full details):

  • Version strings are sliced into alternate, possibly empty non-digit / digit sequences, always starting with a non-digit sequence. 1.0~beta2 is thus ["";1;".";0;"~beta";2].

  • Those sequences are sorted lexicographically. Because of the split as non-digit; digit; non-digit; ..., non-digit sequences are always compared to non-digit sequences (and conversely). For example, the versions a and 1 are sliced into ["a"] and [""; 1], so we have 1 < a because the non-digit component of 1, which is the empty string "", is smaller than "a".

  • For non-digit components, the ordering used is that letters are always smaller than non-letters (for example z < "#"), while non-letters are compared by ASCII order.

  • The ~ character is special as it sorts even before the end of sequence (i.e. before anything shorter: "~" sorts before "", "a~b" before "a"). It's most convenient for pre-releases, allowing 1.0~beta to be before 1.0.

Here is an example of an ordered sequence: ~~, ~, ~beta2, ~beta10, 0.1, 1.0~beta, 1.0, 1.0-test, 1.0.1, 1.0.10, dev, trunk.

Here is a full example:

"foo" { >= "3.12" } & ("bar" | "baz" { !(> "2" & < "3.5") & != "5.1" })



Variables may appear at a few different places in OPAM files and configuration. They can be used in two forms:

  • raw idents: foo < bar
  • within strings, using interpolation, when enclosed in %{ and }%: "%{foo}%/bar"

For both forms, and within values that allow them, the variables are replaced by their contents, if any, just before the value is used. Variable contents can be either strings, booleans or undefined, and automatic conversion may take place using the strings "true" and "false" (leading to an undefined bool when converting from any other string). Undefined values are propagated through boolean expressions, and lead otherwise to context-dependent default values (the empty string and false, unless specified otherwise).

1.2.1 experimental feature: boolean-to-string conversion specifiers

In 1.2.1, the additional syntax "%{var?string-if-true:string-if-false-or-undefined}%" can be used to insert different strings depending on the boolean value of a variable. This is not allowed yet in the main repository.

Additionally, boolean package variables may be combined using the following form: name1+name2+name3:var is the conjunction of var for each of name1, name2 and name3, i.e it is equivalent to name1:var & name2:var & name3:var


The defined variables depend on the specific fields being defined. There are three scopes:

  1. Global variables correspond to the general current configuration (system setup, OPAM configuration, current switch, etc.). For example opam-version, arch, or make.
  2. Package variables have the form package-name:var-name and contain values specific to a given package, e.g. foo:installed is a boolean variable that can be used to check if package foo is installed, foo:lib is its library installation directory. The prefix package-name: can be omitted within the package's own OPAM file (when not shadowed by another variable), in which case the variables will relate to the version of the package being defined. Otherwise, the installed version is always used, and most variables will be undefined when the package isn't installed.
  3. Some fields define their own local variables, like success in the field post-messages

For a comprehensive list of predefined variables, and their current local values, run:

opam config list


"Filters" are formulas based on variables. Their main use is as optional conditions to commands or command arguments, using the postfix-braces syntax:

[ "./configure" "--use-foo" {foo:installed} ]

In build instructions, this adds the "--use-foo" argument only when variable foo:installed is true. This is evaluated just when the command is going to be run.

Filters and package formulas have a different scope and should not be mistaken:

  • Package formulas are over constant packages and versions and can not refer to variables
  • Filters are over variables, and can't refer to packages directly
  • Package formulas denote abstract requirements, they're independent from any given setup. They are solved, not evaluated
  • Filters evaluate at a precise moment in time, in a given setup, to return a value.

The following are allowed in filters:

  • String and boolean literals
  • Idents
  • Parens
  • Logical operators (binary AND &, binary OR |, prefix, unary NOT !)
  • Binary relational operators (=, !=, <, <=, >, >=)

The comparisons are done using Version Order. Relational operators have a higher precedence than logical operators.

Undefined values are propagated through relational operators, and logical operators unless absorbed (undef & false is false, undef | true is true).


Some files can be rewritten using variable interpolation expansion: when looking for file when this is available, if is found, any %{var}% interpolations found in it are replaced by the contents of var and the results are written back to file.

This can also be done explicitly using the command opam config subst "file".

Environment updates

Some fields define updates to environment variables in the form:

<ident> <update-op> <string>

The allowed update operators update-op denote how the string is applied to the environment variable:

  • = override (or set if undefined)
  • += prepend (or set if undefined)
  • =+ append (or set if undefined)
  • := prepend (or set to if undefined) <string>:
  • =: append (or set to if undefined) :<string>


URLs are provided as strings. When pointing to origins for package sources, they may be:

  • raw local filesystem paths
  • ssh addresses user@host:path
  • URLs of the form http://, https://, ftp://, ssh://, file://, rsync://
  • Version control URLs for git, mercurial and darcs: git://, hg://, darcs://
  • Version control bound to a specific URL: <vc>+<scheme>://, e.g. git://, hg+https://, git+file://, etc. (NOTE: this has been added in OPAM 1.2.1)

In addition, version control URLs may be suffixed with the # character and a reference name (branch, commit, HEAD...): git://, hg+file://

The URLs given for user information (e.g. package homepages and bugtrackers) are not concerned and should just load nice in common browsers.

Repository format

A repository is a target that can be pointed to by the opam repository add command and provides metadata (and possibly archives) to OPAM.


An OPAM repository is a directory structure containing the following elements:

  • a packages/ sub-directory, holding all package definitions
  • a compilers/ sub-directory, holding the compilers definitions (used by opam init and opam switch)
  • a repo file with some metadata on the repository itself
  • an archives/ subdirectory that may hold source archives for the packages
  • possibly index.tar.gz and urls.txt files, when serving over HTTP.

All of them are optional, although the repo file is recommended if the repo isn't for purely local use.

The packages definitions are held in package-name.package-version directories below packages/, at any depth. The convention on the official repository is to have a directory per package name, gathering all versions, as such: packages/package-name/package-name.package-version/. If the directory listing gets too large in the future, it may be split into sub-directories by prefix (e.g. packages/p/pa/package-name/package-name.version).

The compiler definitions are held in directories below compilers/, at any depth. The convention is to place them in separate sub-directories depending on the OCaml version they are based on: They should have a name of the form base-ocaml-version+patch (e.g. 4.02.1+BER for the BER compiler), and be placed in a directory compilers/base-ocaml-version/base-ocaml-version+patch/. For the official OCaml releases, the +patch suffix is omitted.

Repo specification

The repo file, placed at the root of a repository, has the following optional fields:

  • opam-version: <string>: File format and repository format version, should be 1.2 as of writing.
  • browse: <string>: An URL where the users may browse available packages online
  • upstream: <string>: The source that this repo is generated and maintained from. Typically, a version-control system address.
  • redirect: [ <string> { <filter> } ... ]: List of URLs to (permanently) redirect to if their filters evaluate to true. Can be used to serve different repositories for different OSes or different versions of OPAM.

Indexes and serving over HTTP(S)

Browsing a large tree hierarchy over HTTP is unpractical. If the repository is to be served over HTTP, the opam-admin tool bundled with OPAM needs to be used to generate digests of all files in the repository, as well as a compressed archive:

opam-admin make --index

should be run at each repository update, and will generate the urls.txt and index.tar.gz files at the root of the repository.

Additionally, if the --index option is omitted, all package archives listed in all packages that aren't present already will be fetched and repackaged inside the archives/ directory, allowing direct download from the server. These are used by opam update even when fetching from non HTTP repositories.

Metadata precedence

When several repositories are configured in a given OPAM installation, all versions of all packages present in them are available. In case of conflict (same version of same package available in two of them), metadata from the repository configured with the highest priority is used.

When pinning a package, metadata is diverted from its normal, repository source. Metadata is searched:

  • in a package-name.opam/ subdirectory of the package source
  • in an opam/ subdirectory of the package source
  • in a package-name.opam file at the root of the package source
  • in an opam file at the root of the package source
  • from the repository if no metadata subdirectory was found above, excluding the opam file is one was found above
  • from a template, opening an editor, if nothing was found in either the package source or the repositories.

Furthermore, the metadata of pinned package is then stored within the switch (at $(opam show --where <package>)), and the opam file can be edited through opam pin edit

NOTE: handling directory or files of the form package-name.opam is a new feature in 1.2.1. It should only be used for source repositories that may hold more than one OPAM package.

Compiler specification

Compilers are specified by

  • a file compiler-name.descr, similar to the package descr files: raw utf8 file starting with a one-line description.

  • a file compiler-name.comp specifying the source and details of the compiler.

The compiler-name.comp file has the following fields:

Note that, since OPAM 1.2.1 all build instructions can be omitted, and that it is therefore possible to delegate all the build process to the packages in packages:.

Package specification

Metadata for a single package is made of all the following files, and should be gathered in a single directory (named package-name.package-version when in a repository).


Descr is a simple utf8 text file -- it doesn't follow the OPAM syntactic conventions. The first line of the file is a short description of the package, suitable for displaying in package listings, and a longer description may follow on next lines.


The url file describes the source of the package and how it may be obtained. It has the following fields:

  • One of src: <string> or archive: <string>, specifying the URL where the package can be downloaded from. When using HTTP or FTP, this should be an archive. The older alternative field names <a id="urlfield-http">http:</a>, local:, <a id="urlfield-git">git:</a>, hg: and <a id="urlfield-darcs">darcs:</a> are deprecated, prefer explicit URLs.

    On the official repository, this should always point to a stable archive over HTTP or FTP.

  • checksum: <string>: the MD5 of the referred-to archive, to warrant integrity. Mandatory on the official repository.

  • mirrors: [ <string> ... ]: an optional list of mirrors. They must use the same protocol as the main URL.


This subdirectory may contain any files or directories (of reasonable size) that will be copied over the root of the package source. opam file fields like patches: refer to files at that same root, so patches are typically included here.

Note that repository archives generated by opam-admin make in archives/ already include these overlay files.


This file is convenient to automate package installation without resorting to external commands like make install. It can be included in files/ but also at the root of the package source, or generated by the build-system.

To avoid duplicating efforts for managing installations, a stand-alone opam-installer tool is provided that can perform installations and uninstallations from these files, without requiring OPAM.

It specifies what files and compilation artefacts must be installed where. All the fields have the form

field: [ <string> { <string> } ]

The following take a list of filenames (relative to the root of the package source) to be installed to the field's respective directory. An optional relative path and destination filename can be given using the postfix braces syntax. A leading ? in the origin filename is stripped and informs OPAM to continue silently when the file is not found.

  • lib: installs to <prefix>/lib/package-name
  • libexec: installs to <prefix>/lib/package-name, but the exec bit is set (since OPAM 1.2.1)
  • bin: installs to <prefix>/bin, with the exec bit set
  • sbin: installs to <prefix>/sbin, with the exec bit set
  • toplevel: installs to <prefix>/lib/toplevel
  • share: installs to <prefix>/share/package-name
  • share_root: installs relative to <prefix>/share (since OPAM 1.2.0)
  • etc: installs to <prefix>/etc/package-name
  • doc: installs to <prefix>/doc/package-name
  • stublibs: installs to <prefix>/lib/stublibs, with the exec bit set

The following are treated slightly differently:

  • man: installs relative to <prefix>/man, with the exception that when the destination is unspecified, the proper destination directory is extracted from the extension of the source file (so that man: [ "foo.1" ] is equivalent to man: [ "foo.1" {"man1/foo.1"} ]
  • misc: requires files to specify an absolute destination, and the user will be prompted before the installation is done.


The main file specifying a package's metadata. The opam lint command is recommended to check the validity and quality of your opam files.

opam files allow the following fields:

  • opam-version: <string> (mandatory): the file format version, should be 1.2 as of writing.

  • name: <string>, version: <string>: the name and version of the package. Both fields are optional when they can be inferred from the directory name (e.g. when the file sits in the repository).

  • maintainer: <string> (mandatory): A contact address for the package maintainer (the format "name <email>" is allowed).

  • authors: [ <string> ... ]: a list of strings listing the original authors of the software.

  • license: [ <string> ... ]: the abbreviated name(s) of the license(s) under which the source software is available.

  • homepage: <string>, doc: <string>, bug-reports: <string>: URLs pointing to the related pages for the package, for user information

  • dev-repo: <string>: the URL of the package's source repository, which may be useful for developers: not to be mistaken with the URL file, which points to the specific packaged version.

  • tags: [ <string> ... ]: an optional list of semantic tags used to classify the packages. The "org:foo" tag is reserved for packages officially distributed by organization ``foo''.

    Tags in the form "flags:<ident>" can be used to pass meaningful flags to OPAM: see the flags: field below. This is mostly intended for compatibility with earlier releases in the 1.2 branch, which will complain about unknown values in the flags: field.

  • patches: [ <string> { <filter> } ... ]: a list of files relative to the project source root (often added through the files/ metadata subdirectory). The listed patch files will be applied sequentially to the source as with the patch command. Variable interpolation is available, so you can specify patches: [ "file" ] to have the patch processed from

    Patches may be applied conditionally by adding filters.

  • substs: [ <string> ... ]: a list of files relative to the project source root. These files will be generated from their .in counterparts, with variable interpolations expanded.

  • build: [ [ <string> { <filter> } ... ] { <filter> } ... ]: the list of commands that will be run in order to compile the package.

    Each command is provided as a list of terms (a command and zero or more arguments) ; individual terms as well as full commands can be made conditional by adding filters: they will be ignored if the filter evaluates to false or is undefined. Variable interpolations are also evaluated. These commands will be executed in sequence, from the root of the package source.

    Any command is allowed, but these should write exclusively to the package's source directory, be non-interactive and perform no network i/o. All libraries, syntax extensions, binaries, platform-specific configuration and package-name.install files should be produced within the source directory subtree during this step. (NOTE: installation instructions used to be included in this step, so you may find examples of older packages that do not respect the above. This behaviour is deprecated)

  • install: [ [ <string> { <filter> } ... ] { <filter> } ... ]: the list of commands that will be run in order to install the package.

    This field follows the exact same format as build:, but should only be used to move products of build: from the build directory to their final destination under the current prefix, and adjust some configuration files there when needed. Commands in install: are executed sequentially after the build is finished. These commands should only write to subdirectories of prefix, without altering the source directory itself.

    This field contains typically just [make "install"]. It is recommended, though, to prefer the usage of a static or generated package-name.install file and omit the install: field.

  • build-doc: [ [ <string> { <filter> } ... ] { <filter> } ... ], build-test: [ [ <string> { <filter> } ... ] { <filter> } ... ]: the list of commands to build documentation and tests. They are processed after the build phase when documentation or tests have been requested. These follow the same specification as the build: field.

  • remove: [ [ <string> { <filter> } ... ] { <filter> } ... ]: the commands used to uninstall the package. It should be the reverse operation of install:, and absent when install: is. It follows the same format as build:.

  • depends: [ <package-formula> ... ]: the package dependencies. This describes the requirements on other packages for this package to be built and installed. It contains a list of package formulas, understood as a conjunction.

    As an addition to the package formula format, the version constraints may be prefixed by dependency flags. These are one of build, test and doc and limit the meaning of the dependency:

    • build dependencies are no longer needed at run-time: they won't trigger recompilations of your package.
    • test dependencies are only needed when building tests (i.e. by instructions in the build-test field)
    • likewise, doc dependecies are only required when building the package documentation

    Dependency flags must be first, and linked by &:

    depends: [
      "foo" {build}
      "bar" {build & doc}
      "baz" {build & >= "3.14"}
  • depopts: [ <string> { <dependency-flags> } ... ]: the package optional dependencies. This flag is similar to depends: in format, but with some restrictions. It contains packages that will be used, if present, by the package being defined, either during build or runtime, but that are not required for its installation. The implementation uses this information to define build order and trigger recompilations, but won't automatically install depopts when installing the package.

    The optional dependencies may have dependency flags, but they may not specify version constraints nor formulas. depopts: can be combined with conflicts: to add version constraints on the optional dependencies.

  • conflicts: [ <string> { <version-constraint> } ... ]: a list of package names with optional version constraints indicating that the current package can't coexist with those.

  • depexts: [ [ [ <string> ... ] [ <string> ... ] ] ... ]: the package external dependencies. This field is a list that can be used for describing the dependencies of the package toward software or packages external to the OPAM ecosystem, for various systems. It contains pairs of lists of the form [ predicates ext-packages ]. predicates is used to select the element of the list based on the current system: it is a list of tags (strings) that can correspond to the OS, architecture or distribution. The predicates is used as a conjunction: the pair will only be selected when all tags are active. The resulting ext-packages should be identifiers of packages recognised by the system's package manager.

    There is currently no definite specification for the precise tags you should use, but the closest thing is the opam-depext project. The depexts information can be retrieved through the opam list --external command.

  • messages: [ <string> { <filter> } ... ]: used to display an additional (one-line) message when prompting a solution implying the given package. The typical use-case is to tell the user that some functionality will not be available as some optional dependencies are not installed.

  • post-messages: [ <string> { <filter> } ... ]: allows to print specific messages to the user after the end of installation. The special boolean variable failure is defined in the scope of the filter, and can be used to print messages in case there was an error (typically, a hint on how it can be resolved, or a link to an open issue). success is also defined as syntactic sugar for !failure.

  • available: [ <filter> ]: can be used to add constraints on the OS and OCaml versions currently in use, using the built-in os and ocaml-version variables. In case the filter is not valid, the package is disabled. The os and ocaml-version fields are deprecated, please use available instead in newly created packages.

    This field is evaluated before request solving or any actions take place ; it can only refer to global variables, since it shouldn't depend on the current switch state. An unavailable package won't generally be seen on the system, except with opam list -A.

  • flags: [ <ident> ... ]: specify package flags that may alter package behaviour. Currently available flags are:

    • light-uninstall: the package's uninstall instructions don't require the package source. This is currently inferred when the only uninstall instructions have the form ocamlfind remove..., but making it explicit is preferred (since OPAM 1.2.0).
    • verbose: when this is present, the stdout of the package's build and install instructions will be printed to the user (since OPAM 1.2.1).
    • plugin: the package installs a program named opam-<name> and may be auto-installed and run with opam <name> (since OPAM 1.2.2 ; the use is discouraged in the 1.2 branch for compatibility, use tag: "flags:plugin" instead)
  • features: [ <ident> <string> { <filter> } ... ] (EXPERIMENTAL): this field is currently experimental and shouldn't be used on the main package repository. It allows to define custom variables that better document what features are available in a given package build. Each feature is defined as an identifier, a documentation string, and a filter expression. The filter expression can evaluate to either a boolean or a string, and the defined identifier can be used as a variable in any filter (but recursive features are not allowed and will be undefined).

    This is typically useful to pass appropriate flags to ./configure scripts, depending on what is installed.