📦 pkgin and pkgsrc

Binary packages in seconds with pkgin, source builds with pkgsrc, dependencies, autoremove and a vulnerability check, on a real NetBSD 11.1 machine, with an apt-to-pkgin table to keep.

Video: pkgin and pkgsrc (NetBSD video)
Prefer to watch? This short video runs this page's main commands on a real NetBSD 11.1 machine, with on-screen captions and a synthetic voiceover (an AI voice trained on the author's own recording). Click to play, or watch it on YouTube.
pkgin -y install figlet              # install a binary package
pkgin -y remove figlet               # remove it
cd /usr/pkgsrc/misc/figlet && make install clean   # or build it from source

NetBSD keeps all third-party software in pkgsrc, apart from the base system. You can install ready-made binary packages with pkgin, which feels like apt, or build the same packages from source with make. This page covers both, plus dependencies, autoremove, updates, a vulnerability check and a table from apt to pkgin.

Every example ran for real on NetBSD 11.1 (amd64) in a virtual machine, as an ordinary user, with root commands marked #. The output you see is the output the machine gave.

Two ways to get software

NetBSD has one collection of third-party software, called pkgsrc, and two ways to use it. You can install a ready-made binary package with pkgin, which takes seconds, or you can build the same package from source with make, which takes a few minutes and lets you change how it is built. Both produce the same kind of installed package, and the same tools manage them afterwards.

Every example here ran for real on NetBSD 11.1 (amd64) in a virtual machine, as an ordinary user called bsd. Commands that need root start with # because NetBSD has no sudo by default. Packages install under /usr/pkg, apart from the base system. Start by asking pkgin where it gets packages from:

$ pkgin -v | head -n 1
pkgin 26.4.0 (using SQLite 3.53.4)
$ grep -v '^#' /usr/pkg/etc/pkgin/repositories.conf
https://cdn.netbsd.org/pub/pkgsrc/packages/NetBSD/$arch/11.0/All
$ pkg_info | head -n 3
pkg_install-20260227 Package management and administration tools for pkgsrc
sqlite3-3.53.4      SQL Database Engine in a C Library
pkgin-26.4.0        Apt / yum like tool for managing pkgsrc binary packages

The repository is a directory of binary packages for this release and this CPU. Notice that the path says 11.0: NetBSD 11.1 uses the packages built for the 11.0 branch, and that is correct. pkg_info lists what is already installed, and pkgin itself is a package like any other.

Finding a package

pkgin search matches names and descriptions, much like apt search. A search that finds nothing exits with status 1, which makes it easy to use in a script:

$ pkgin search ^figlet
figlet-2.2.5nb2      Print text banners in fancy ASCII art characters
figlet-fonts-20021023nb1  Additional fonts for figlet

=: package is installed and up-to-date
<: package is installed but newer version is available
>: installed package has a greater version than available package
$ pkgin pkg-descr figlet | head -n 4
Information for https://cdn.netbsd.org/pub/pkgsrc/packages/NetBSD/x86_64/11.0/All/figlet-2.2.5nb2.tgz:
Description:
Figlet is a program that creates large ASCII art characters out of ordinary
screen characters
$ pkgin show-deps cowsay
direct dependencies for cowsay-3.04nb6
	perl>=5.0
$ pkgin search nosuchpkg; echo "exit status $?"
No results found for nosuchpkg
exit status 1

pkg-descr prints the long description, and show-deps lists what a package needs before you install it. cowsay needs perl, so installing it will bring perl along. Packages also have categories, which is how pkgsrc is organised on disk:

$ pkgin show-all-categories | head -n 5
archivers
audio
benchmarks
biology
cad
$ pkgin show-category games | head -n 3
puzzles-20220127nb15 Collection of small one-player puzzle games by Simon Tatham
stone-soup-sdl-0.31.0nb9 Dungeon Crawl Stone Soup - roguelike adventure (tileset version)
kanatest-0.4.8nb60   Flash-card program to memorise Japanese kana

The listing is sorted by what the repository holds, so the packages you see will differ from the ones here.

Installing and removing

pkgin install does the download, the dependency resolution and the installation. As root, because it writes to /usr/pkg:

# pkgin -y install cowsay figlet
calculating dependencies...done.

3 packages to install:
  cowsay-3.04nb6 figlet-2.2.5nb2 perl-5.44.0nb2

0 to remove, 0 to refresh, 0 to upgrade, 3 to install
13M to download, 76M of additional disk space will be used

[1/3] downloading cowsay-3.04nb6.tgz done.
[2/3] downloading figlet-2.2.5nb2.tgz done.
[3/3] downloading perl-5.44.0nb2.tgz done.
[1/3] installing perl-5.44.0nb2...
[2/3] installing cowsay-3.04nb6...
[3/3] installing figlet-2.2.5nb2...
pkg_install warnings: 0, errors: 0
reading local summary...
processing local summary...
$ cowsay moo
 _____
< moo >
 -----
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
$ figlet NetBSD
 _   _      _   ____ ____  ____
| \ | | ___| |_| __ ) ___||  _ \
|  \| |/ _ \ __|  _ \___ \| | | |
| |\  |  __/ |_| |_) |__) | |_| |
|_| \_|\___|\__|____/____/|____/

$ pkg_info | grep -E 'cowsay|figlet|perl'
perl-5.44.0nb2      Practical Extraction and Report Language
cowsay-3.04nb6      Configurable talking cow
figlet-2.2.5nb2     Print text banners in fancy ASCII art characters

The -y answers yes to the question pkgin asks. pkg_info -L lists the files a package installed, and pkg_info -F with the -I option tells you which package owns a file, much like dpkg -S:

$ pkg_info -L cowsay | head -n 3
Information for cowsay-3.04nb6:

Files:
$ pkg_info -FI /usr/pkg/bin/cowsay
cowsay-3.04nb6      Configurable talking cow

Like a good Unix tool, pkgin prints little when everything works. Check that the command exists afterwards instead of waiting for a message.

Security: pkg_admin audit

pkgsrc can tell you which installed packages have a known vulnerability. It needs a list, which you fetch first:

# pkg_admin fetch-pkg-vulnerabilities
# pkg_admin audit
Package perl-5.44.0nb2 has a symlink-attack vulnerability, see https://nvd.nist.gov/vuln/detail/CVE-2011-4116
(exit status 1)

Each line names a package and a vulnerability report. This is data that changes daily, so your own output will differ. An empty result means no known problem. Here perl, which the install above pulled in, has an old report against it. The command exits with status 1 when it finds something, which makes it usable in a cron job. pkgsrc also checks a package against this list before it builds one from source, and refuses to build one with a known hole unless you tell it to.

To check the files of installed packages, and see how a package was built:

# pkg_admin check
Checked 3030 files from 7 packages.
Done.
$ pkg_info -B figlet | grep -E 'MACHINE_ARCH|OPSYS|BUILD_DATE'
BUILD_DATE=2025-12-24 04:00:49 +0000
MACHINE_ARCH=x86_64
OPSYS=NetBSD

check compares the files on disk with what each package recorded. A silent run ending in Done means all is well.

Dependencies, keep and autoremove

pkgin remembers which packages you asked for and which came only as dependencies. The first are marked keep:

$ pkgin show-keep
cowsay-3.04nb6       Configurable talking cow
figlet-2.2.5nb2      Print text banners in fancy ASCII art characters
pkgin-26.4.0         Apt / yum like tool for managing pkgsrc binary packages
tree-1.8.0           Print a text or HTML tree diagram of a directory structure
$ pkgin show-rev-deps perl
local reverse dependency tree for perl-5.44.0nb2
	cowsay-3.04nb6

show-rev-deps lists what depends on a package. Here only cowsay needs perl. Now remove cowsay, and see what is left behind:

# pkgin -y remove cowsay
1 packages to delete:
  cowsay-3.04nb6

[1/1] removing cowsay-3.04nb6...
pkg_install warnings: 0, errors: 0
reading local summary...
processing local summary...
$ pkgin show-no-keep
perl-5.44.0nb2       Practical Extraction and Report Language
pkg_install-20260227 Package management and administration tools for pkgsrc
sqlite3-3.53.4       SQL Database Engine in a C Library
$ pkg_info | grep perl; echo "exit status $?"
perl-5.44.0nb2      Practical Extraction and Report Language
exit status 0

perl is still installed, but nothing needs it any more, and it is not marked keep, so pkgin calls it removable. The autoremove command takes out the dependencies nothing needs. pkg_install and sqlite3 stay, because pkgin itself needs them. Try it with -n first, which only prints what it would do:

# pkgin -n autoremove
1 packages to be autoremoved:
perl-5.44.0nb2
# pkgin -y autoremove
1 packages to be autoremoved:
  perl-5.44.0nb2

[1/1] removing perl-5.44.0nb2...
pkg_install warnings: 0, errors: 0
reading local summary...
processing local summary...
$ pkg_info | grep perl; echo "exit status $?"
exit status 1

If you want to keep a dependency, pkgin keep name marks it, and pkgin export writes the keep list to a file you can import on another machine. That is a simple way to repeat an installation.

Updating

pkgin update refreshes the list of packages the repository has. pkgin upgrade installs newer versions of what you have. Look before you act, with -n:

# pkgin update
processing remote summary (https://cdn.netbsd.org/pub/pkgsrc/packages/NetBSD/x86_64/11.0/All)...
database for https://cdn.netbsd.org/pub/pkgsrc/packages/NetBSD/x86_64/11.0/All is up-to-date
# pkgin -n upgrade
calculating dependencies...done.
nothing to do.

When nothing newer exists, there is nothing to do and the dry run says so. Packages are not part of the base system, and they update on their own schedule. The base system updates with a new release or with a new build of the same source tree, not with pkgin. Run both: the system when a release comes, and pkgin upgrade regularly.

pkgin clean removes the downloaded package files from the cache, which is worth doing now and then on a small disk.

Building from source with pkgsrc

The packages are built from a tree of recipes, also called pkgsrc. Get the current tree, which is about sixty megabytes, and unpack it in /usr. The unpacking takes a couple of minutes, because the tree holds a great many small files:

# ftp -o /tmp/pkgsrc.tar.xz http://cdn.netbsd.org/pub/pkgsrc/current/pkgsrc.tar.xz 2>&1 | tail -n 1
# cd /usr && tar xJf /tmp/pkgsrc.tar.xz
$ ls /usr/pkgsrc | head -n 8
CVS
Makefile
README-all.html
README.html
README.md
archivers
audio
benchmarks

Each package is a directory, in a category: /usr/pkgsrc/misc/figlet holds the recipe for figlet. A recipe is small. Nothing here is the program itself, only the instructions for fetching, patching and building it:

$ ls /usr/pkgsrc/misc/figlet
CVS
DESCR
Makefile
PLIST
README.html
distinfo
patches
$ cat /usr/pkgsrc/misc/figlet/DESCR
Figlet is a program that creates large ASCII art characters out of ordinary
screen characters

      _ _ _          _   _     _
     | (_) | _____  | |_| |__ (_)___
     | | | |/ / _ \ | __| '_ \| / __|
     | | |   <  __/ | |_| | | | \__ \_
     |_|_|_|\_\___|  \__|_| |_|_|___(_)


Figlet can print in a variety of fonts, both left-to-right and right-to-left.
Figlet comes with several fonts.  Also, many other fonts are avaiable,
including Hebrew, Cyrillic (Russian), and Greek.

Remove the binary package, then build it again from source. make install does everything, including the build tools it needs and does not yet have, and clean removes the work directory afterwards. Only the main steps are shown here, the build prints hundreds of lines:

# pkgin -y remove figlet
1 packages to delete:
  figlet-2.2.5nb2

[1/1] removing figlet-2.2.5nb2...
pkg_install warnings: 0, errors: 0
reading local summary...
processing local summary...
# cd /usr/pkgsrc/misc/figlet && make install clean 2>&1 | grep -E '^===> (Extracting|Building|Installing) for figlet'
===> Extracting for figlet-2.2.5nb2
===> Building for figlet-2.2.5nb2
===> Installing for figlet-2.2.5nb2
$ figlet source

 ___  ___  _   _ _ __ ___ ___
/ __|/ _ \| | | | '__/ __/ _ \
\__ \ (_) | |_| | | | (_|  __/
|___/\___/ \__,_|_|  \___\___|

$ pkg_info | grep figlet
figlet-2.2.5nb2     Print text banners in fancy ASCII art characters

The same package is installed again, but this time it was built here, from the distfile that pkgsrc downloaded and checked against the checksum in the distinfo file. Building takes longer, and it is how you get options a binary package does not have: put settings in /etc/mk.conf, and run make show-options in a package directory to see what can be changed.

Linux to NetBSD side by side

The package commands map closely:

 - apt update: pkgin update.
 - apt install name: pkgin install name.
 - apt remove name: pkgin remove name.
 - apt autoremove: pkgin autoremove.
 - apt upgrade: pkgin upgrade.
 - apt search name: pkgin search name.
 - apt show name: pkgin pkg-descr name, and pkgin show-deps name.
 - dpkg -L name: pkg_info -L name.
 - dpkg -S file: pkg_info -F file.
 - dpkg -l: pkg_info, or pkgin list.
 - apt source and building: make install in /usr/pkgsrc/category/name.
 - A security tracker: pkg_admin audit.

Packages put their files in /usr/pkg and their configuration in /usr/pkg/etc, so a package never touches the base system. To add a service from a package, copy the example rc.d script from /usr/pkg/share/examples/rc.d to /etc/rc.d, and enable it in /etc/rc.conf as before.

When something goes wrong

The common failures are about permissions and about a package that does not exist:

$ pkgin -y install figlet
pkgin: You don't have enough rights for this operation.
(exit status 1)
$ pkgin search nosuchpkg; echo "exit status $?"
No results found for nosuchpkg
exit status 1
$ pkgin -y remove nosuchpkg; echo "exit status $?"
no such installed package nosuchpkg
no packages to delete
exit status 1
$ pkg_info nosuchpkg; echo "exit status $?"
pkg_info: can't find package `nosuchpkg'
exit status 1

An ordinary user cannot install, and pkgin says so. For a missing package, search exits with 1, remove says there is no such installed package, and pkg_info exits with 1 and says no matching package. If pkgin cannot reach the repository, check the network and the date first, and then the path in repositories.conf. Run pkgin update after you change it.