Skip to content
Building only what you want

Building only what you want

The build tags that leave protocols, user directories, the admin API and the provisioner out of the binary, and what each saves.

Each protocol is behind a build tag, and a tag leaves it out entirely: no listener, no parser, no dependency, no code.

go install -tags nonfs,nowebdav,nosftp,nos3 github.com/go-fileshare/fileshare@latest   # SMB only
go build   -tags nosmb,nonfs,nosftp,nos3 .                                            # WebDAV only

Where the people come from is behind tags of its own: nosql leaves out the three database drivers, noldap the LDAP client.

buildsize
everything31.2 MB
-tags noldap30.9 MB
-tags nosftp30.6 MB
-tags noopenpubkey (no opkssh logins over SFTP)about 2 MB less
-tags nos331.1 MB
-tags nonfs,nowebdav,nosftp,nos3 (SMB only)28.1 MB
-tags nopartitioned (no apfs, btrfs, xfs, zfs)29.2 MB
-tags nosql20.2 MB
-tags nosql,noldap19.8 MB
-tags nosql,noldap,nonfs,nowebdav,nosftp,nos316.2 MB

These are the figures the fileshare README gives, measured before the admin API arrived; the table below is the later measurement.

The admin API, and nogrpc

The admin API brought gRPC and protobuf in, and they are behind nogrpc (linux/amd64, measured 2026-09-29, when the rows above had grown to 34.1 MB for everything):

buildsize
everything, with the admin API46.1 MB
-tags nogrpc34.4 MB
-tags nosql,noldap,nogrpc22.5 MB

gRPC costs 11.7 MB — the plugin measurement below, taken again, now that it is here for a reason of its own. A site that manages its shares in files does not need to carry it.

An admin block in a nogrpc build is refused

Rather than served without one: a configuration that asks for the API and starts without it does not do what it says.

nogrpc leaves out the admin API and, with it, the provisioner. Health and metrics are plain HTTP and stay.

-tags noprovisioner leaves out only the provisioner, the privileged fileshare provisioner role, and go-fsctl’s zfs, btrfs and projquota with it: a server that never serves volumes need not carry the code that creates them. fileshare provisioner in such a build says so rather than “unknown command”.

nosql is by a distance the biggest lever: PostgreSQL, MySQL and SQLite together weigh 11.7 MB, more than every protocol in this program put together. A site whose users are in the file wants it. The drivers are imported by the command and not by the library that uses them, which is what makes the choice a build tag rather than a fork.

A protocol this binary was built without

A configuration naming one is told that, rather than “there is no such protocol” — the difference between a typo and a build tag. The same holds for opkssh_client_id under noopenpubkey and an admin block under nogrpc.

Why not subprocess plugins

It was measured rather than argued: hashicorp/go-plugin brings gRPC and protobuf, which cost 13.2 MB on their own — more than this entire binary with all three protocols and every driver in it. A plugin host would be twice the size before loading anything, and each plugin binary would carry gRPC again.

For attack surface, a tag is also the stronger tool for anything you do not run: code that was never compiled cannot be reached, sandboxed or not.

What tags do not give is isolation between the protocols you do run, nor a way to add a protocol without recompiling. Both are real, and both are arguments for a process boundary rather than for a smaller binary — which is one process per protocol, using this same binary, not a plugin framework.

Created on by tannevaled

Modified on by tannevaled