Library / SDK
goreleaser/nfpm avatar
goreleaser/nfpm

nFPM: building deb, rpm, apk, ipk and Arch packages from one YAML file

nFPM is Not FPM - a simple deb, rpm, apk, ipk, and arch linux packager written in Go

2,654 stars191 forksGoMIT

At a glance

What is it?
nFPM is a Go binary and library that turns a single config file into native packages for five Linux formats, with no Ruby or system packaging tools in the loop. It is aimed at Go and CI-driven projects that already ship a compiled artifact and need packages as a side effect.
Who is it for?
Adopt nFPM if you ship a compiled artifact from CI and want deb, rpm, apk, ipk and Arch packages produced from one YAML file without a Ruby toolchain. Skip it if you need distro-native source builds, signed repository metadata, or packaging behaviour that only rpmbuild or debhelper can express.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 10 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

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

Editorial analysis

The problem nFPM solves: five package formats, one config file

Producing a .deb and an .rpm for the same release usually means two toolchains, two sets of metadata, and two ways to get it wrong. The README states the motivation directly: fpm is "great", but the author considered it a problem that it depends on ruby, tar and other software. nFPM was written as a binary and a library that makes as few assumptions as possible.

The audience is narrow and identifiable. You already have a built artifact: a Go binary, a set of static files, a compiled service. You want that artifact wrapped in the native package format of each distribution you support, and you want the wrapping to happen in CI on a machine that has no Debian or RPM tooling installed. The repository layout confirms the scope: apk/, arch/, deb/, rpm/, ipk/ and msix/ sit side by side at the top level, each holding the code for one format.

What nFPM is not: it is not a build system. It does not compile your program, fetch dependencies, or resolve a source tree. It takes files that exist and metadata you supply, and writes a package. That boundary is the whole design.

How nFPM builds a package: config in, format-specific writer out

The mechanism is a config file plus per-format writers. nfpm.go sits at the repository root as the entry point, and the format directories hold the code that knows how to lay out a Debian control archive, an RPM header and payload, an apk, an ipk or an Arch package. A single YAML document describes the package once; each writer translates the parts it understands into its own format.

The dependency list in go.mod shows how much of the work is done in-process rather than by shelling out. The project pulls in github.com/blakesmith/ar for ar archives (the container format Debian packages use), github.com/klauspost/pgzip and github.com/klauspost/compress for compression, github.com/ulikunitz/xz for xz, github.com/sassoftware/go-rpmutils plus go.digitalxero.dev/rpm for RPM structures, and go.digitalxero.dev/go-msix for MSIX. Signing support comes from github.com/ProtonMail/gopenpgp and go-crypto. The CLI layer is github.com/spf13/cobra with github.com/charmbracelet/fang for the terminal interface, and configuration is validated against a schema generated with github.com/invopop/jsonschema.

The practical consequence is that nFPM is a self-contained binary. Nothing in the dependency graph requires a system rpm or dpkg to be present. The trade-off is the mirror image: nFPM reimplements format handling rather than delegating to the distribution's own tools, so anything those tools do beyond assembling a package is outside its reach.

Installing nFPM and building your first package

The README points to the documentation site for install instructions rather than listing commands inline, so the authoritative steps live at nfpm.goreleaser.com/docs/install/. The project also publishes its own packages, and the Dockerfile in the repository shows how the Alpine image consumes one: it copies an nfpm .apk into /tmp and installs it with apk's untrusted flag, then sets /usr/bin/nfpm as the entry point.

That Dockerfile is the clearest documented example of a working install path, because it is checked into the repository:

dockerfile
FROM alpine:3.24.1@sha256:28bd5fe8b56d1bd048e5babf5b10710ebe0bae67db86916198a6eec434943f8b
ARG TARGETPLATFORM
COPY $TARGETPLATFORM/nfpm*.apk /tmp/
RUN apk add --allow-untrusted /tmp/nfpm_*.apk
ENTRYPOINT ["/usr/bin/nfpm"]

Because nFPM is also a Go module, it can be pulled into a Go project as a library. The module path is declared in go.mod:

bash
go get github.com/goreleaser/nfpm/v2

For a first real use, the shape is a YAML file describing the package and a command that reads it. The configuration reference at nfpm.goreleaser.com/docs/configuration/ is where the accepted keys are listed, and the quick-start page at nfpm.goreleaser.com/docs/quick-start/ walks through a minimal file. The README does not document the exact package subcommand flags inline, so treat the documentation site as the source for the precise command before you script it.

What you should see is a package file written to the output path named in your config, in the format you asked for. Verify the flag names against the configuration and quick-start pages before wiring them into CI, since the README itself only links to them.

Where nFPM stops: what it does not do for you

nFPM assembles packages. It does not build them the way a distribution maintainer would. There is no source-tree compilation, no debhelper-style maintainer script generation, and no dependency resolution against a repository index. If your packaging process needs to run a build inside a chroot, apply distro patches, or produce a source package alongside the binary one, nFPM is the wrong layer and you want the distribution's own tooling.

Repository metadata is the other boundary. Signing a package is supported through the OpenPGP dependencies, but publishing a signed apt or yum repository with its own Release or repomd metadata is a separate job. nFPM gives you the artifact; the index around it is yours to generate.

The README is also silent on rollback and upgrade semantics. It does not describe how a package built by nFPM behaves when a user downgrades, or what happens to files left behind by a previous version. Those behaviours come from the package manager on the target system and from the scripts you supply, not from nFPM, and the documentation does not claim otherwise. If your deployment depends on precise upgrade or rollback behaviour, that has to be verified against your own packages on the target distributions.

nFPM against fpm, and against building packages natively

The README names fpm as the inspiration and the comparison point. fpm is a Ruby program that wraps existing system tools, and the README says its dependence on ruby, tar and other software was the reason nFPM exists. The difference in approach is not cosmetic. fpm orchestrates the tools a distribution already ships; nFPM implements the archive and metadata writing itself in Go, which is why it can run as a single static binary on a machine with no packaging tools installed.

That choice cuts both ways. A Go implementation is easier to drop into a container and easier to call from a Go program, and its behaviour does not shift with the version of rpm or dpkg on the build host. A Ruby wrapper, by contrast, inherits whatever the underlying tools do, including their edge cases and their handling of unusual metadata. If your packages rely on behaviour that only the real rpmbuild or dpkg-deb produces, fpm is closer to that behaviour by construction.

The third option is not a tool at all: writing a spec file or a debian/ directory by hand and letting the distribution's build system do the work. That path gives you the most control and the most fidelity, at the cost of maintaining one packaging definition per format. nFPM's value is collapsing those definitions into one file, and that value disappears if the formats diverge enough that the shared config stops describing them.

Maintenance, releases and what the MIT licence means here

The repository is not archived, and the last push was on 2026-09-21. Releases are frequent: v2.47.0 on 2026-06-20, v2.46.3 on 2026-04-18, and v2.46.2 the same day as v2.46.3. A patch release landing hours after another suggests the maintainers ship fixes quickly rather than batching them.

The upgrade cost is mostly config drift. Because the config schema is generated and validated with invopop/jsonschema, a key that disappears or changes shape between versions will be caught rather than silently ignored, which is the better failure mode but still means a version bump can break a build. The deprecation/ directory at the repository root indicates the project tracks removals explicitly, so the changelog and release notes are where to look before upgrading a pinned version. The go.mod declares go 1.26.4, so building nFPM from source requires a toolchain at least that recent.

On licensing: nFPM is MIT, and LICENSE.md is the file to read. MIT is permissive and does not impose copyleft obligations on your own packages, but nFPM's dependencies carry their own licences, and the compiled binary you distribute includes them. That is a question for your own review, not something the README answers.

Editorial conclusion

Adopt nFPM if you ship a compiled artifact from CI and want deb, rpm, apk, ipk and Arch packages produced from one YAML file without a Ruby toolchain. Skip it if you need distro-native source builds, signed repository metadata, or packaging behaviour that only rpmbuild or debhelper can express. Before committing, verify that the package formats you target are the ones the repository actually implements, check the config reference for the keys your packages need, and confirm the licence terms in LICENSE.md for your own distribution.

Frequently asked questions

What is goreleaser/nfpm?

It is a packager written in Go that produces deb, rpm, apk, ipk and Arch Linux packages, and it can be used either as a standalone binary or as a Go library. The README describes it as a simpler, zero-dependency alternative to fpm.

How do I install nFPM?

The README links to the install page at nfpm.goreleaser.com/docs/install/ rather than listing steps inline. It also ships its own packages, and the repository Dockerfile installs one into an Alpine image with apk add --allow-untrusted before setting /usr/bin/nfpm as the entry point.

How do I configure nFPM for a deb or rpm build?

Configuration is a YAML file, and the accepted keys are listed in the configuration reference at nfpm.goreleaser.com/docs/configuration/. The same file is used across formats, with each format's writer reading the parts it understands.

Official sources

  1. goreleaser/nfpm on GitHub
  2. License: MIT
  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/goreleaser-nfpm.svg)](https://hysenlabs.com/projects/goreleaser-nfpm)