Multi-select (Ctrl/Cmd+click toggle, Shift+click range, right-click the
active selection for bulk actions - same conventions as a native file
manager):
- Print Labels (N) / Export CSV (N) for any mix of individually-picked
assets and whole folders. Labels/export now take asset_ids/folder_ids
instead of a single asset_id/folder_id.
- Edit Status..., Check Out..., Duplicate, Move to..., and Delete, bulk
versions of the existing single-asset actions. Checkout/Move modals
were generalized to accept an array of ids instead of just one; status
editing got its own lightweight POST /app/assets/{id}/status endpoint
(assets.SetStatus) so a bulk status change doesn't need to resend every
other field the way a full PATCH would.
Labels:
- Choose QR (a /scan/<tag> URL, for a phone camera) or Code128 barcode
(the bare Asset ID, for a USB scanner typing into the search box) via a
format selector on the print page. New barcodeDataURI using
github.com/boombuler/barcode alongside the existing QR generator.
- "Start at #" lets printing resume partway into an already-used sheet
instead of wasting it on a fresh one.
- Added the Avery 5260 label template (same grid as 5160, rounded
corners, so it isn't flagged approximate).
Also: the configured Site Name now shows on the login page too, not just
the authenticated navbar.
9.8 KiB
inventree
A small, self-contained IT asset inventory system. The heart of inventree is a nested folder tree — like a file manager — for organizing physical and virtual IT assets (servers, switches, laptops, printers, etc.).
- Single compiled Go binary, embedded HTML templates and static assets
- SQLite storage (WAL mode, foreign keys, migrations)
- Bootstrap 5 UI, minimal vanilla JavaScript (no Node/React/build step)
- Session-based auth with two roles: Admin and User
- Custom, admin-defined asset types with custom fields
- CSV import/export, full-text-ish search with breadcrumbs
Quick start
go build -o inventree ./cmd/inventree
./inventree serve
Then open http://localhost:8080 and log in with:
Username: admin
Password: admin
(This default account is created intentionally on first run. Change or disable it via the Users admin page once you're up and running.)
The database file is created automatically at data/inventree.db on first
run, with migrations applied and seed data (default statuses, item types,
and the admin account) inserted.
CLI
inventree # same as `inventree serve`
inventree serve # start the web server
inventree version # print the version
inventree database migrate # apply pending migrations and exit
inventree database backup [path] # write a consistent VACUUM INTO snapshot
serve flags:
| Flag | Default | Description |
|---|---|---|
-addr |
:8080 |
Listen address |
-db |
data/inventree.db |
Path to the SQLite database file |
-secure-cookies |
false |
Mark the session cookie Secure (enable when serving over HTTPS) |
/healthz is available for load balancer / container health checks.
The inventory tree
The Inventory page is the default page after login and the center of the application: a folder/asset tree on the left, and a detail panel on the right that shows whatever is selected (a folder's contents, or a single asset).
- Folders can nest arbitrarily deep, and contain both subfolders and assets.
- Expand/collapse state is remembered per user (persisted server-side), and folder contents are fetched lazily via small AJAX requests — the page never fully reloads when you browse the tree.
- Drag and drop folders and assets onto another folder (or onto "Inventory" itself) to move them. Admin only.
- Right-click for everything: it's meant to feel like a native file manager. Right-click a folder, an asset, a breadcrumb crumb, or empty tree/panel background for the actions available there (New Subfolder, Add Asset, Rename, Check Out, Move, Print Label, Delete, …) instead of hunting for a toolbar button. The main panel itself stays blank until you actually click into a folder or asset — browsing happens in the tree.
- Deleting a folder that still contains subfolders or assets requires confirmation, and offers a safe "move contents elsewhere" option instead of an accidental cascade. A "permanently delete everything inside" option is also available for when that's genuinely what you want.
- Search (top of the tree pane) looks across asset ID, name, folder name, item type, assigned user, notes, and custom field values, and shows each result's full folder breadcrumb.
Item types and custom fields
Admins can define arbitrary asset types (Laptop, Switch, Firewall, …) under Item Types, each with its own set of custom fields (text, long text, number, date, boolean, dropdown, URL, IP address), marked required or not, with a default value and display order. A representative starter set of types and fields is seeded on first run — feel free to edit or delete it.
Checkout, quantity, and contacts
- Check out / check in: right-click an asset → Check Out… to assign it to a user (or clear the assignment to check it back in). Works from any asset row, not just its detail view.
- Quantity vs. unique: item types have a Unique flag (checked by default). Unique types — a laptop, a server — get one asset row per physical unit, same as before. Uncheck it for bulk/consumable types (a USB cable, a box of screws) and assets of that type are tracked as a single row with a Quantity and +/- steppers in the asset panel and folder tables, instead of one row per unit. Flipping a type back to Unique clamps any existing quantities back down to 1.
- Contacts: under Settings → Users, a third role alongside Admin and User. Contacts can't sign in at all — they exist purely so you can assign assets to end users (e.g. "this laptop belongs to Jane in Accounting") without creating them a login account. A blank password is fine when creating one.
QR/barcode asset tags and printable labels
Every asset can have a scannable label printed for it: right-click an asset for Print Label, or right-click a folder for Print Labels… (every asset in that folder, recursively). Choose the code format on the print page itself:
- QR code — encodes an absolute
/scan/<Asset ID>URL, so scanning it with a phone camera opens straight to that asset. - Barcode (Code128) — encodes the bare Asset ID, meant for a dedicated USB barcode scanner typing it into whatever's focused (e.g. the app's search box).
The print page also supports three label sheet layouts, switchable from a dropdown:
- Avery 5160 / 5260 (1" x 2-5/8", 30/sheet) — standard address labels (5260 is the same grid, just rounded corners), exact published dimensions.
- 61526 asset tag labels (3/4" x 2", ~48/sheet) — the grid/margins here are a best-effort layout, not a verified spec sheet, so print one test page on plain paper and check it against a real label before committing a full (often non-refundable) sheet.
Printing a batch without wasting sheet space: Ctrl/Cmd+click (toggle) or Shift+click (range) multiple folders/assets in the tree, the same way you would in a file manager, then right-click the selection for Print Labels (N) — along with Export CSV (N), Edit Status…, Check Out…, Duplicate, Move to…, and Delete, all bulk versions of the single-item actions. On the print page itself, Start at # lets you resume printing partway into an already-used sheet (position 1 = top-left, counting left-to-right, top-to-bottom) instead of starting a fresh one over a few peeled-off labels.
CSV import / export
- Export: from the tree's right-click menu, or
/export/assets.csv(optionally scoped to a folder, with?recursive=1to include subfolders). Includes aQuantitycolumn and onecf_<field_key>column per distinct custom field in use. - Folder-scoped import: right-click a folder → Import CSV… imports
every row directly into that folder. No
Foldercolumn needed — that's the whole point of doing it from a specific folder. Never available at the top level. - Global import: Settings → Import / Export has the full-featured
version — a CSV with a
Foldercolumn (a/-separated path, e.g.Main Office/Network) that can optionally auto-create missing folders — plus a separate CSV import for bulk-adding/updating Statuses (Name,Color). Both matching-by-name/Asset-ID semantics and full column references with examples are documented right on that page.
A full backup/restore of everything (folders, assets, types, custom fields,
statuses, users) is just inventree database backup — it's a consistent
snapshot of the whole SQLite database.
Project layout
cmd/inventree/ CLI entrypoint (serve, version, database migrate/backup)
internal/
auth/ session management, secure cookies
database/ SQLite connection, pragmas, migrations
migrations/ embedded .sql migration files
models/ shared domain types
folders/ nested folder tree
assets/ asset CRUD, search, CSV import/export
itemtypes/ admin-defined types + custom field definitions
users/ accounts
statuses/ configurable asset statuses
settings/ key/value app settings
web/ HTTP router, handlers, template rendering
web/
templates/ Go html/template pages and partials (embedded)
static/ Bootstrap 5, Bootstrap Icons, app.css, app.js (embedded)
deploy/ systemd unit example
Development
go build ./...
go vet ./...
go test ./...
The SQLite driver is modernc.org/sqlite,
a pure-Go implementation, so CGO_ENABLED=0 builds work out of the box and
the compiled binary has no C library dependencies.
Docker
docker compose up --build
This builds the image, starts inventree on port 8080, and persists the
database in a named volume (inventree-data, mounted at /app/data).
Or directly:
docker build -t inventree .
docker run -p 8080:8080 -v inventree-data:/app/data inventree
systemd
See deploy/inventree.service for an example unit. Adjust the paths, then:
sudo useradd --system --home /opt/inventree --shell /usr/sbin/nologin inventree
sudo mkdir -p /opt/inventree/data
sudo cp inventree /opt/inventree/inventree
sudo chown -R inventree:inventree /opt/inventree
sudo cp deploy/inventree.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now inventree
Scope
inventree is intentionally a focused MVP: folders, assets, custom types, statuses, users, search, and CSV import/export. It does not include ticketing, purchasing, monitoring, RMM, MDM, or accounting features — if you need those, look elsewhere and integrate via CSV.