Syncthing — Structure#
Layout pattern#
Standard Go Layout with lib/ as primary library root (non-standard naming)
Syncthing follows the standard Go layout in spirit (cmd/ for binaries, internal/ for private code) but uses lib/ rather than pkg/ for its reusable packages. This is an intentional architectural choice: lib/ signals “library-quality packages that external GUI wrappers and tools may import,” whereas internal/ is reserved for a small set of truly private utilities. The result is a bimodal package hierarchy with ~40 public-ish packages in lib/ and 7 strictly private packages in internal/.
Directory map#
syncthing/
├── assets/ # Status tray icon images (platform-specific icons)
│ └── statusicons/
├── cmd/ # All binary entry points
│ ├── syncthing/ # Main syncthing application + embedded CLI
│ │ └── cli/ # REST API CLI client (subcommand of main binary)
│ ├── stdiscosrv/ # Global discovery server (production service)
│ ├── strelaysrv/ # Relay server (production service)
│ ├── dev/ # Developer tools (10 small utilities)
│ └── infra/ # Infrastructure services (crash, relay pool, upgrades, usage)
│ ├── stcrashreceiver/
│ ├── strelaypoolsrv/
│ ├── stupgrades/
│ └── ursrv/
├── etc/ # System integration (init scripts, service files)
│ ├── linux-systemd/ # systemd unit files
│ ├── macos-launchd/ # launchd plist
│ ├── freebsd-rc/ # FreeBSD rc.d
│ └── ... # upstart, runit, solaris-smf, firewall-ufw
├── gui/ # Web UI static assets (4 color themes)
│ ├── default/ # Default theme (AngularJS SPA + vendor JS)
│ ├── dark/
│ ├── light/
│ └── black/
├── internal/ # Private packages (not importable outside module)
│ ├── blob/ # Binary blob storage abstraction
│ ├── db/ # Database interface (SQLite-backed)
│ ├── gen/ # Code generation helpers
│ ├── itererr/ # Iterator with error propagation
│ ├── protoutil/ # Protobuf encoding/decoding utilities
│ ├── slogutil/ # Structured logging (slog) helpers
│ └── timeutil/ # Time utility functions
├── lib/ # Core application library (~40 packages)
│ ├── api/ # REST API server (HTTP handlers, auth, CORS)
│ ├── assets/ # Embedded GUI asset serving
│ ├── beacon/ # UDP broadcast beacon for local device discovery
│ ├── build/ # Build metadata (version, tags, build info)
│ ├── config/ # Configuration loading, validation, migration
│ ├── connections/ # Connection management (QUIC, TCP, relay transport)
│ ├── dialer/ # Low-level connection dialing
│ ├── discover/ # Device discovery (local UDP + global HTTPS)
│ ├── events/ # Internal event bus (typed events, subscriptions)
│ ├── fs/ # Filesystem abstraction (real, fake, case-folding, MTime)
│ ├── geoip/ # MaxMind GeoIP database integration (for relay/disco)
│ ├── httpcache/ # HTTP caching layer
│ ├── ignore/ # .stignore pattern matching
│ ├── locations/ # Platform-specific config/data/log paths
│ ├── model/ # Core sync engine (the largest and most critical package)
│ ├── nat/ # NAT traversal coordination
│ ├── netutil/ # Network utility functions
│ ├── osutil/ # OS-level utilities (atomic file ops, etc.)
│ ├── pmp/ # NAT-PMP protocol client
│ ├── protocol/ # Block Exchange Protocol (BEP) implementation
│ ├── rand/ # Cryptographic random number utilities
│ ├── rc/ # REST client library (used by CLI subcommand)
│ ├── relay/ # Relay protocol client
│ ├── scanner/ # File scanner, block hasher, metadata collector
│ ├── semaphore/ # Counting semaphore primitive
│ ├── signature/ # Code signature/update verification
│ ├── sliceutil/ # Generic slice utilities
│ ├── stats/ # Per-device and per-folder statistics
│ ├── stringutil/ # String utilities
│ ├── structutil/ # Struct reflection utilities
│ ├── stun/ # STUN client for NAT traversal
│ ├── svcutil/ # Service supervisor utilities (suture helpers)
│ ├── syncthing/ # Top-level application assembly (wires lib/* together)
│ ├── syncutil/ # Sync primitives (mutex with tracing, etc.)
│ ├── testutil/ # Shared test helpers
│ ├── tlsutil/ # TLS certificate generation and loading
│ ├── upgrade/ # Auto-upgrade mechanism
│ ├── upnp/ # UPnP NAT port mapping
│ ├── ur/ # Usage reporting client
│ ├── versioner/ # File versioning strategies (trash can, staggered, etc.)
│ └── watchaggregator/ # Filesystem watcher event aggregation and debouncing
├── man/ # Man page source (refreshed by script)
├── meta/ # Project metadata (compatibility declarations)
├── proto/ # Protocol Buffer definitions
│ ├── bep/ # Block Exchange Protocol messages
│ ├── apiproto/ # REST API protobuf types
│ ├── dbproto/ # Database record types
│ ├── discoproto/ # Discovery protocol messages
│ └── discosrv/ # Discovery server service definition
├── relnotes/ # Per-version release notes
├── script/ # Build helper Go scripts (authors, copyrights, etc.)
├── test/ # Integration test infrastructure
│ ├── h1/ h2/ h3/ h4/ # Test host configurations (pre-configured Syncthing homes)
│ └── logs/
├── build.go # Custom build script (go run build.go ...)
├── build.sh # Shell wrapper for build.go
├── buf.yaml # Buf (protobuf toolchain) configuration
├── buf.gen.yaml # Buf code generation configuration
└── Dockerfile* # Multiple Dockerfiles, one per serviceEntry points#
| Binary | File | Purpose |
|---|---|---|
syncthing | cmd/syncthing/main.go | Main application: file sync daemon + embedded web UI |
syncthing cli | cmd/syncthing/cli/main.go | REST API CLI client (subcommand of syncthing binary) |
stdiscosrv | cmd/stdiscosrv/main.go | Global discovery server (production; maps device ID → address) |
strelaysrv | cmd/strelaysrv/main.go | Relay server (TCP relay for devices behind NAT) |
stcrashreceiver | cmd/infra/stcrashreceiver/main.go | Infrastructure: crash report collection service |
strelaypoolsrv | cmd/infra/strelaypoolsrv/main.go | Infrastructure: relay pool registry service |
stupgrades | cmd/infra/stupgrades/main.go | Infrastructure: binary update server |
ursrv | cmd/infra/ursrv/main.go | Infrastructure: anonymous usage reporting server |
stfinddevice | cmd/dev/stfinddevice/main.go | Dev tool: locate device on local network |
stfindignored | cmd/dev/stfindignored/main.go | Dev tool: show which files are ignored |
stdisco | cmd/dev/stdisco/main.go | Dev tool: query discovery server |
stfileinfo | cmd/dev/stfileinfo/main.go | Dev tool: show BEP file info for a path |
stwatchfile | cmd/dev/stwatchfile/main.go | Dev tool: test filesystem watcher |
stevents | cmd/dev/stevents/main.go | Dev tool: stream events via REST API |
stsigtool | cmd/dev/stsigtool/main.go | Dev tool: sign/verify release artifacts |
stcompdirs | cmd/dev/stcompdirs/main.go | Dev tool: compare two directory trees |
stvanity | cmd/dev/stvanity/main.go | Dev tool: generate device ID with prefix |
stgenfiles | cmd/dev/stgenfiles/main.go | Dev tool: generate test file trees |
Package organization#
Internal packages (
internal/): 7 packages that are strictly private to the module —db(SQLite-backed storage),blob(binary object storage),gen(codegen),itererr(iterator error handling),protoutil(protobuf encoding),slogutil(structured logging helpers),timeutil(time utilities). These are the true implementation internals, not meant for external consumers.Public packages (
lib/): 40 packages structured as a cohesive application library. The most critical are:lib/model— Core sync engine; largest package in the codebase. Manages folder state, device connections, file transfers.lib/protocol— BEP (Block Exchange Protocol) implementation; the on-wire format for all sync traffic.lib/fs— Filesystem abstraction with multiple implementations (basic, case-sensitive wrapper, MTime-tracking). Essential for cross-platform correctness.lib/config— Configuration with live-reload, migration, and validation.lib/connections— Transport management (QUIC, TCP, relay-based connections).lib/discover— Both local (UDP beacon) and global (HTTPS) device discovery.lib/syncthing— Application assembly layer that wiresmodel,api,connections,discover,config,eventstogether into the running application.
Layering: The package dependency graph has a clear layering:
- Primitives (
rand,semaphore,syncutil,sliceutil,stringutil,structutil,osutil,netutil) — no cross-dependencies - Domain utilities (
fs,ignore,scanner,versioner,events,stats,tlsutil) — depend on primitives - Protocol/Network (
protocol,beacon,dialer,relay,stun,nat,upnp,pmp,discover,connections) — depend on domain utilities - Application core (
model,api,config) — depend on most of the above - Assembly (
lib/syncthing) — wires all core components together under a supervisor tree - Binaries (
cmd/syncthing) — thin shell that calls intolib/syncthing
- Primitives (
Build system#
- Build tool: Custom Go build script (
go run build.go), wrapped bybuild.sh. No Makefile. The build script (build.go) uses the//go:build toolstag and handles compilation, testing, packaging, and release artifact production for all target platforms. - Key targets:
go run build.go— buildssyncthingbinarygo run build.go -goos <OS> -goarch <ARCH>— cross-compilego run build.go test— run test suitego run build.go install— install to GOPATH- Individual infra services built separately by their Dockerfiles
- Docker: Yes — 8 Dockerfiles at the repo root, one per service (
Dockerfile,Dockerfile.builder,Dockerfile.stdiscosrv,Dockerfile.strelaysrv,Dockerfile.stcrashreceiver,Dockerfile.strelaypoolsrv,Dockerfile.stupgrades,Dockerfile.ursrv). Multi-stage builds are used. - Protobuf: Managed via
buftoolchain (buf.yaml,buf.gen.yaml); proto sources live inproto/and generated Go code lives alongside thelib/packages.
Notable structural decisions#
lib/overpkg/naming: Syncthing predates the widespread adoption of thepkg/convention and useslib/to signal “importable library.” This has stayed stable since the early days and enables the ecosystem of third-party GUI wrappers (Syncthing-GTK, Syncthing-macOS, etc.) that importlib/packages directly.lib/syncthingas an explicit assembly package: Rather than doing all wiring incmd/syncthing/main.go, Syncthing introduceslib/syncthingas a dedicated package that constructs and starts the supervised service tree. This makes the main binary trivially thin and enables alternative entry points (e.g., embedding syncthing in other applications).Infrastructure services co-located with the application:
stdiscosrv,strelaysrv, and allinfra/services live in the same repository. Each has its own Dockerfile and can be deployed independently. This is unusual — most projects would split these into separate repositories — but it ensures protocol compatibility is maintained in lockstep.Multiple Dockerfiles at the root: 8 Dockerfiles at the repository root is a deliberate trade-off: simple and self-documenting, but visually noisy. Each service’s build context is the full repository, which is required because they all import from
lib/.proto/with domain-partitioned subdirectories: Protocol Buffer definitions are split by semantic domain (bep,dbproto,discoproto,apiproto,discosrv), keeping the wire formats modular and allowing independent evolution of each protocol component.GUI as static assets in 4 themes: The web UI (AngularJS SPA) ships as embedded static assets in 4 color variants. The
script/genassets.gotool generates a Go file embedding them; this avoids runtime filesystem dependencies and keeps the binary self-contained.test/h1-h4pre-configured host directories: Integration tests spin up multiple real Syncthing instances using pre-seeded home directories (test/h1/throughtest/h4/), testing actual sync behavior rather than mocked components. This reflects a culture of integration testing over unit testing for the core sync path.