Self-hosted · material inventory

How much is actually left?

Put it on a kitchen scale and type in what the scale says. filahub subtracts the empty weight of the container and of the drybox it lives in, and keeps the result — for every spool, bottle and pail, every time.

on the scale gross, container and box included 1,954 g
container Panchroma PLA · cardboard · 1 kg − 140 g
drybox Drybox A − 1,450 g
material left of 1,000 g nominal 364 g 36%
Real numbers from the weigh-in dialog below, down to the colour of the percentage.
The filahub overview: an icon rail down the left, a header with an area switcher set to Personal, a store switcher set to Filament 1.75 mm and an identifier field, three tiles showing 4,194 g remaining across nine materials with one bar segment per material, the three materials running low as small spool gauges, and a remaining value of €117.42. Below them the shelf: one spool per material with a coloured fill ring, grouped by drybox, and a panel on the right for F01 Panchroma PLA with its gauge, trend, totals and weigh-in history.
Nine materials, 4,194 g left, three of them running low — and F01 open in the panel on the right.

Weighing

The empty weight is the whole problem

A spool that reads 1,590 g on the scale might be empty or might hold half a kilo — it depends entirely on what the spool and the box underneath it weigh. So filahub stores those two numbers as data and does the subtraction for you:

remaining = gross − container tare − drybox tare

Nothing is derived from slicer estimates or print jobs. The remaining quantity is whatever the last weigh-in said, so it is wrong only if the scale was.

Give a material a short identifier — F01 — and write it on the label. Typing it into the field in the header — it is there on every page — opens the weigh-in dialog on that one. The field searches every store, because whoever reads a code off a spool in their hand has no idea which store happens to be selected. Standing at the printer, the whole loop is: scale, F01, number, done.

The fill level is coloured on one scale throughout:

  • 10% and under
  • to 25%
  • to 50%
  • above
The weigh-in dialog over the overview: an entered total weight of 1954 g, a highlighted result of 364 g at 36 percent, and a breakdown listing 140 g container tare, 1,450 g drybox tare for Drybox A, and 1,590 g total tare.
The dialog shows the tare it is about to subtract, before you save.

Every weigh-in is kept, not overwritten. A material's page lists them with gross and net side by side, which is what turns an inventory into a consumption record: 1,000 g in March, 812 g in April, 590 g in June, 364 g in August.

Those points also draw a line. From the newest weigh-in and the oldest one within the last ninety days filahub works out a rate — on this spool, 25 g a week — and how long the rest lasts at that rate: about fifteen more weeks. It is deliberately that simple, a straight line through two points rather than a forecast, and it feeds into nothing else. A weigh-in that reads more than the one before is a new spool or a corrected tare, not negative consumption, so the trend goes quiet instead of going wrong.

A material's detail page: a spool gauge at 364 g of 1,000 g nominal, 36 percent and approximately 122 metres, the trend of minus 25 g per week with about 15 weeks left, a chart of the four weigh-ins, cards for consumed grams, total tare, last gross weight and remaining value, a details list naming the container and drybox with their tare, and the weighing history table with four dated entries.
Consumed, total tare, last gross reading, the remaining value of what is on the spool — and the line the four weigh-ins draw.

Stores

Not everything you print comes on a spool

If you sinter powder or print with resin, it needs somewhere to live. A store groups what belongs together and carries the settings that apply to everything inside it — which kind of material it holds, and for filament, which diameter:

Filament
Spools and reels. Remaining amount also in metres.
Powder
Sintering powder in bags or buckets. Grams only.
Resin
Liquid resin. Remaining amount also in litres.

Up to five of them, switched in the header; the overview, the tiles and the filters all follow that choice. The diameter belongs to the store rather than to each material, because it changes the answer more than anything else does: 1 kg of PLA is about 335 m at 1.75 mm, and only about 126 m at 2.85 mm.

Grams are still what you weigh and what you type in. But next to the remaining amount you also see roughly how much is left in the unit that matters — and it is prefixed with approx. on purpose. The number rests on a density that is usually an estimate, and filahub would rather say so than pretend. Powder gets no second unit at all: bulk density depends on grain size and packing, so any figure would be a guess, and a wrong number is worse than none.

The stores page with three stores: Filament 1.75 mm holding nine materials and shared with one friend, Powder holding one material, and Resin holding two materials and shared with one friend.
Three stores, three kinds of material — and each one says whether it leaves your account.

Containers

A container is not always a spool

What holds your material is a container, and every container type has a form: spool, bag, bottle, pail, cartridge — or other, because not every container in the world fits five boxes.

The form is a hint, not a rule. In a resin store, bottles and cartridges sort to the top under a heading that says “Fits Resin”, but every container stays selectable. If you have a reason to put filament in a bucket, filahub is not going to argue.

The new container type dialog over a list of seven container types, with the form dropdown open showing spool, bag, bottle, pail, cartridge and other, and partly behind it the calculator that works out the empty weight from the weight of a full container and its nominal fill.
Six forms, and a calculator that works the empty weight out from one weigh-in of a full container.

An empty weight is a fact, so it is shared

Weighing an empty Prusament spool is a job exactly one person should ever have to do. filahub ships a catalogue that everyone on an instance draws from, with four levels:

manufacturer → series → version → size

The version level is the one that earns its keep. Polymaker moved its PLA from a 215 g plastic spool to a 140 g cardboard one, and both are in the catalogue with the period each was sold in. Pick the wrong one and every weigh-in on that spool is off by 75 g — quietly, forever.

A size carries the empty weight and, where it is known, outer diameter, width and bore. Those three only show up for spools; a bottle has no bore.

The preset catalogue with Polymaker expanded: the Fiberon series in 500 g and 2 kg sizes, and Panchroma, formerly PolyTerra PLA, with a cardboard spool from 2021 at 140 g and an older plastic spool up to 2020 at 215 g, each listing empty weight and dimensions.
Polymaker expanded: the two spool versions, with the dates that tell them apart.

Hide any manufacturer, series, version or single size you will never own. Hiding changes only your own picker — a container already assigned to a material stays valid and keeps its tare. You can also copy a preset into your own, freely editable container type when yours differs from the catalogue.

Found a wrong number? Send a correction, with the reason you know better. Suggestions go into a moderation queue; an accepted one is applied to the catalogue and becomes visible to everyone, and a rejected one comes back with the reason. That is also how resin and powder entries will arrive. None ship with the app, and that is deliberate: a wrong starting value is worse than a missing one.

Sharing

Friends see what you choose, store by store

You have 200 g of PETG left, you need 600, and someone you know has a full spool sitting in a drybox. Swap friend codes — something like FH-A2B3-C4D5 — and you can see it. Nobody can find you without the code, so your account cannot be discovered by guessing names.

What you show is decided per store and per friend, and nothing is shared by default:

Nothing
The store stays completely hidden. This is where every friendship starts.
Search only
Your material turns up when your friend searches for something specific. No browsing.
Whole store
Your friend can open that store and look through it.

Prices never leave. Neither do notes, purchase dates, dryboxes, weigh-in history, or the store's own name — a store name is free text and can name a place. What a friend gets is one plain list, so they cannot tell whether two matches came from one store or two, or that you keep separate stores at all. Found something useful? “Ask” sends a message through the bot.

The friends page: a friend code card, a form to add a friend by code or Telegram name, and a friend's card listing all three of your stores with their own sharing level — whole store, nothing and search only — above a single read-only line showing what that friend shows you.
One row per store, per friend. A store you have not shared says so rather than being left out.

An organization is one stock, several people

A company, a university print hub or a makerspace has one shelf of filament and a dozen people reaching into it. Create an organization, give it stores, and everyone you let in works on the same stock — not a copy, not a shared view, the stock itself. The first switcher in the header decides which side you are looking at, and nothing mixes: your personal stock stays exactly as private as it was.

Not everyone in a workshop should be able to delete a store, so membership comes at one of four levels, each including the ones below it:

View
Look up and search the stock.
Weigh
Also weigh — the everyday act of booking material out again.
Record
Also add, change and import material, and maintain containers and dryboxes.
Manage
Also create stores, invite people and assign levels.

Buttons you are not allowed to use are not shown, rather than shown greyed out. There are two ways in: a join code — ORG-… — that anyone can enter, and which can never hand out “Manage”, because a code gets passed around and pinned to a wall and whoever found it should not end up running the place; or a personal invitation at whichever level you pick, which takes effect only once the invited person accepts.

An organization page for Makerspace North with four members at the levels manage, record, weigh and view, a card for inviting someone by friend code or Telegram name with the level the invitation carries, and the start of the open joining card below it.
Four members, four levels, and an invitation that carries the level you picked for it.

Bulk import

A whole order in one pass

filahub generates a prompt. Hand it to an LLM together with your order confirmation, paste the JSON that comes back, and you get an editable table — manufacturer, type, colour, nominal weight, price, quantity. Correct what the model got wrong, drop the lines you do not want, pick the store it all goes into, and only then does anything get written.

A line with quantity 2 becomes two separate materials, because two spools are two spools and they will not be weighed together.

The JSON keys stay German — typ, hersteller, nenngewicht — whichever language the interface is set to. They are part of the schema the server validates against, so translating them would break the import.

An order confirmation usually carries your name, your address and how you paid. That goes to the model's provider, not to filahub, so redact whatever it does not need — the page says as much where you paste.

The import page: pasted JSON with German keys in a text area, and below it the review step with a picker for the target store, a purchase date, a table of four order lines from Polymaker, Prusament, Bambu Lab and SUNLU, and a button labelled import 5 materials.
Four order lines, one of them a double — five materials to be created.

Self-hosting

Runs on your own server

One container from ghcr.io/grimbixcode/filahub and a PostgreSQL database. Pending migrations are applied at startup, so an empty database sets itself up and an update is a pull and a restart.

Sign-in goes through Telegram — either the official login widget or a six-digit code from your own bot — with a whitelist of user IDs. Open registration exists but is off unless you set it, because the moment someone else signs in you are the data controller for their data, and nobody should end up there by overlooking a variable.

The interface is available in English and German, and the language belongs to the account rather than the browser. Number, weight and date formats are a separate setting — an English interface does not force you into American dates. Dark and light theme follow the system unless you pin one.

Environment variables, a ready-to-use Compose file and the reverse-proxy setup are in the README; what the app stores and what running it for other people means is in PRIVACY.md. It is free software under the AGPL-3.0, so a fork you host yourself stays yours — you just have to pass the source on to whoever uses it.

filahub on a phone: the overview as stacked cards, each with a fill ring, the percentage, remaining grams and metres, the drybox, and buttons to log usage and to weigh.
Cards on a phone — the device that is actually next to the scale.