Library / SDK
jordansissel/fpm avatar
jordansissel/fpm

jordansissel/fpm: build deb, rpm and osxpkg packages from the command line

Effing package management! Build packages for multiple platforms (deb, rpm, etc) with great ease and sanity.

11,517 stars1,065 forksRubyNOASSERTION

At a glance

What is it?
fpm is a Ruby command line tool that turns a directory, tarball, gem, npm or python module into a native package for deb, rpm, pacman, freebsd or osxpkg targets. It is best for teams that need one package format now and a different one later, and worst when you need a fully distro-compliant spec file.
Who is it for?
Adopt fpm when you ship the same payload to several distributions and do not want to maintain a debian/ tree and an rpm spec side by side. Do not adopt it when a distribution's packaging policy requires hand-written maintainer scripts, split subpackages or a reviewable spec, because fpm generates those artifacts rather than expressing them.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 60 days ago.
What is it written in?
Mainly Ruby, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 13, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • jordansissel/fpm11,517 ★ · +8
Star history
Repository2026-09-222026-11-13
jordansissel/fpm11.5k11.5k

8 Stars in the last 52 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

What fpm solves, and for whom

The README is unusually direct about the motivation. Packaging is "done wrong" in some situations, small tweaks can fix it, and sometimes no package exists at all for the tool you need. The author also describes switching between Ubuntu and CentOS, two package systems with different policies and support tools, and wanting to avoid learning both from scratch. fpm exists so you can say "here's my install dir and here's some dependencies; please make a package".

The audience follows from that. If you build an internal agent, a CLI binary or a vendored runtime and you need to hand it to a Debian fleet and a RHEL fleet in the same week, fpm is aimed at you. It is also aimed at people who already have a package and want to change it: the README lists tweaking existing packages, removing files, changing metadata and dependencies, and stripping pre, post and maintainer scripts. That second use is easy to overlook. fpm is not only a builder, it is also a package editor for formats you do not want to open by hand.

What it is not is a replacement for a distribution's own build tooling. The project principles say "make it work, then make it right, then make it fast", which is a statement about priorities: correctness of the generated artifact comes after the fact that it builds at all.

Sources, targets, and the conversion model

The architecture is a conversion pipeline. The README lists the inputs (sources) and outputs (targets) separately, and the tool's job is to move a payload from one side to the other. Sources include gem, python modules, pear, directories, tar and tar.gz archives, rpm, deb, node packages (npm) and pacman packages. Targets are deb, rpm, solaris, freebsd, tar, directories, Mac OS X .pkg files (osxpkg) and pacman.

The interesting part is that rpm and deb appear on both lists. That means an existing rpm can be read and re-emitted as a deb, and vice versa. For a team migrating off one distribution, this is the feature that matters most: you do not need the original build scripts to produce a package for the new platform, only the package you already ship. The same property makes fpm useful as an inspection and surgery tool, since you can take a vendor package, strip its scripts, and repackage it.

Some sources download for you. The README says gem is "even autodownloaded for you", python modules and pear "also downloads for you". That matters for reproducibility, because a conversion that reaches the network is not the same as one that reads a local file. If your build must run offline, the archive and directory sources are the ones to plan around.

The Dockerfile shows the runtime dependency set the project itself installs on Ubuntu 20.04: ruby, ruby-dev, libarchive-tools, cpio, debsigs, pacman, rpm, squashfs-tools, xz-utils, zip, gcc, libc6-dev, make, lintian and git. The presence of rpm, pacman and debsigs there is a concrete signal that target support depends on the corresponding platform tools being present, not only on the Ruby gem.

Installing fpm and building a first deb

The README points to the installation guide at fpm.readthedocs.io for per-platform instructions, and the repository ships a gemspec, so RubyGems is the likely route. The Makefile has an install target that builds the gem and runs gem install on it.

bash
gem install fpm

After that, fpm should be on your PATH. The README's own summary of the job is "here's my install dir and here's some dependencies; please make a package", so the natural first exercise is turning a staged directory into a deb. Lay your application out under a directory exactly as it should appear on the target filesystem relative to /, then run fpm with the directory source and the deb target. The README lists deb among the targets and directories among the sources; the CLI reference under docs/ is where the per-target flags are described, so check it rather than guessing at spellings.

Once a package exists, the useful verification steps are the ones from the target platform's own tooling: dpkg-deb -I prints the control metadata of a deb and dpkg-deb -c lists the file paths inside it. For an rpm, rpm -qip prints the package information and rpm -qlp lists its contents. Those commands come from dpkg and rpm, not from fpm, and they are what tell you whether the metadata and dependencies came out the way you intended.

The same payload to a different format is a change of target, not a change of layout. The README's source and target lists are the map: pick the source that matches what you have, pick the target that matches where it is going, and let the platform tools inspect the result.

Where fpm is the wrong tool

The most honest limitation is stated by the project itself: packaging is sometimes "done wrong (because you can't do it right for all situations)". A converter that infers a spec or a control file from a payload will produce something that installs, but it will not produce the artifact a distribution's review process expects. If your package must be accepted into a distribution archive, or must follow that distribution's policy on split subpackages, scriptlets and file ownership, you are better served by writing the native recipe and letting fpm handle only the throwaway internal builds.

The second limitation is environmental. The Dockerfile installs rpm, pacman, debsigs, cpio and lintian alongside Ruby. That is a fair indication that producing a given target format depends on tooling for that format being installed on the build host. A container that has only Ruby and the fpm gem is not obviously sufficient for every target, and the README does not claim otherwise.

The third is reproducibility. Because gem, python and pear sources can download their inputs, two runs at different times can package different content. If you need byte-identical rebuilds, prefer the tar and directory sources and pin the payload yourself.

Finally, fpm is a Ruby gem. Hosts that cannot run Ruby, or teams that have standardized on a single compiled build tool for supply-chain reasons, will find the dependency awkward even though the packages it emits have no Ruby requirement of their own.

How fpm differs from nfpm and GoReleaser

A close alternative is nfpm. The difference in approach is structural. nfpm is driven by a configuration file: you describe the package in YAML, including contents, scripts and dependencies, and the tool renders the deb or rpm from that description. fpm is driven by command line flags and by reading an existing artifact. With fpm you point at a directory or an rpm and describe only the metadata you want to override; with nfpm you write the whole package definition down.

That makes nfpm the better fit when the package definition should live in version control next to the application and be reviewed like code. It makes fpm the better fit when the input already exists as a package or a tarball and rewriting it as a declarative manifest would be duplicated work. GoReleaser occupies a third position: it is a release pipeline for Go projects that can call nfpm to produce packages as one stage of a larger flow. If your build is already GoReleaser shaped, adding fpm means adding a second packaging concept rather than extending the one you have.

None of these is a drop-in for the others. The decision is about where the package definition lives: in a config file, in command line invocations, or in a release pipeline.

Maintenance, releases and licence

The repository is not archived, and the last push was on 2026-09-14. Releases are steady rather than rapid: v1.16.0 on 2024-12-09, v1.17.0 on 2025-10-02, and v1.18.0 on 2026-08-26. That cadence suits a tool whose job is stable conversion between formats, but it also means you should not expect a quick turnaround on a newly introduced distribution format.

The upgrade cost is mostly in the gem. The Makefile builds the gem from the gemspec, and the version comes from lib/fpm/version.rb, so a pinned version in your build image is straightforward to control. The larger operational cost is the build host, not the gem: the Dockerfile shows the set of platform tools the project installs for its own test and release images, and those are the things that drift when distributions change their package tooling.

The repository's LICENSE file is present, but the GitHub metadata reports the licence as NOASSERTION, meaning no standard licence identifier was detected. The README does not discuss licensing terms. If you are packaging fpm itself, or vendoring parts of it, read the LICENSE file in the repository directly and treat the absence of a recognized identifier as something to resolve before you rely on it. This is not legal advice; it is a pointer to the file that answers the question.

Editorial conclusion

Adopt fpm when you ship the same payload to several distributions and do not want to maintain a debian/ tree and an rpm spec side by side. Do not adopt it when a distribution's packaging policy requires hand-written maintainer scripts, split subpackages or a reviewable spec, because fpm generates those artifacts rather than expressing them. Before committing, install the gem, convert one real tarball using the CLI reference under docs/, and inspect the resulting package with dpkg-deb -I or rpm -qip to confirm the metadata and dependencies came out the way you expect.

Frequently asked questions

Which Linux package manager is best?

That is not a question fpm answers; it produces packages for several managers rather than replacing one. The README lists deb, rpm, solaris, freebsd, tar, directories, osxpkg and pacman as targets, so the choice stays with the distribution you deploy to.

What is the purpose of a package manager?

The README describes the problem it works around rather than defining package managers: sometimes no package exists for the tool you need, and sometimes packaging is done wrong for your situation. fpm's stated goal is to let you say "here's my install dir and here's some dependencies; please make a package".

What package formats can fpm produce?

The README lists deb, rpm, solaris, freebsd, tar, directories, Mac OS X .pkg files (osxpkg) and pacman as targets. Sources include gem, python modules, pear, directories, tar and tar.gz archives, rpm, deb, node packages (npm) and pacman packages.

Can fpm convert an existing rpm into a deb?

Yes. rpm and deb both appear on the README's source and target lists, so an existing package can be read and re-emitted in the other format. That is the path to take when you do not have the original build scripts.

Does fpm need the distribution's packaging tools installed?

The project's own Dockerfile installs rpm, pacman, debsigs, cpio, squashfs-tools, lintian and related tools alongside Ruby on Ubuntu 20.04. That suggests producing a given target format depends on tooling for that format being present on the build host.

Official sources

  1. Issues
  2. jordansissel/fpm on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/jordansissel-fpm.svg)](https://hysenlabs.com/projects/jordansissel-fpm)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/jordansissel-fpm.svg)](https://hysenlabs.com/projects/jordansissel-fpm)

Was this useful?