Grocy: Running a Household Like a Warehouse
An ERP for your fridge, and the discipline it demands in return

Contents
Grocy describes itself as “ERP beyond your fridge”, and the joke lands because it is entirely accurate. Bernd Bestel has built a small, sincere enterprise resource planning system for a domestic household: stock levels with locations and best-before dates, quantity-unit conversions, purchase and consumption transactions, price history, minimum stock amounts that generate shopping lists, chore scheduling with assignees, battery-change tracking, and an equipment folder for the manual of the boiler.
It is genuinely well made. The PHP is tidy, it runs on SQLite with no external database, the API is complete, the documentation is honest, and the whole thing fits in about 120MB of RAM. As a piece of software I have very few complaints.
As a thing to live with, it has the highest abandonment rate of anything in my rack, and I want to be straight about that up front, because every enthusiastic Grocy post I read before installing it skipped the part that matters. Grocy’s problem has nothing to do with Grocy. It is that a stock system is only as good as its inputs, and the inputs are a human being remembering to tell a website that they ate some yoghurt.
What it actually models
Think of your kitchen as a warehouse and the vocabulary falls out immediately.
Products have a name, a default quantity unit, a location, a default best-before period, and optionally a minimum stock amount and a barcode. Stock is the current inventory: how many, where, expiring when, bought at what price. Everything that changes stock is a transaction: purchase, consume, open, transfer, or inventory correction.
The quantity-unit system is where you see the ERP DNA. A product is bought in one unit and consumed in another, with a declared conversion factor. Flour arrives in 1kg bags and leaves in grams. Milk arrives in litres and leaves in millilitres. Beer arrives in crates of 24 and leaves in bottles. Grocy handles all of that correctly, including the fractional stock that results, and it will tell you that you have 0.62 of a bag of flour without blinking.
Layered on top:
- Minimum stock amounts drive an automatic shopping list. Set flour’s minimum to 1kg, drop below, and it appears on the list without anyone deciding.
- Recipes can check themselves against stock. “Can I cook this tonight?” becomes a query the software answers, and one click consumes every ingredient.
- Chores are recurring household tasks with schedules, assignees and a “last done” record. Descale the kettle, clean the oven filter, turn the mattress.
- Batteries get their own tracker, because the smoke alarm’s battery has a lifespan and nobody remembers when they changed it.
- Equipment stores manuals as PDFs against an appliance, which sounds trivial and is the feature I have used most reliably, because a boiler manual is never findable at the moment the boiler needs it.
The container
Grocy is the easiest install in this batch by a wide margin. One container, SQLite, no dependencies.
| |
That is it. Browse to it through your proxy, log in with admin / admin, change that immediately, and you have a working household ERP.
| |
The entire state lives in one SQLite file at /config/data/grocy.db, which is a design decision I have a lot of time for. It means backup is trivial, it means the thing starts in under a second, and it means there is no Postgres to tune, no Redis to forget about, and no migration that can eat your Saturday. I have argued this case generally in SQLite Is a Production Database (For Your Homelab, Anyway) and Grocy is close to the perfect example: one household, a handful of writes an hour, a database measured in megabytes.
Settings worth changing on day one, under Settings → Manage users / Settings: your default locale for date formats, the “stock overview” default view, and — importantly — turn off the features you will never use. Grocy has a feature-flag system:
| |
Switching off the modules you do not want removes them from the navigation entirely, and a Grocy with three modules is a Grocy you might actually keep using. Mine runs stock, chores and equipment. Tasks went off in week two, because I already have a task list and running two is how both end up empty — a point I laboured in Vikunja and the Self-Hosted Task-List Trap.
Barcodes, or: the only way this survives
Here is the arithmetic that decides everything. A weekly shop is forty items. Entering forty items by hand, through a web form, with quantities and best-before dates, takes about twenty minutes. Nobody does that twice. I have watched three friends install Grocy, do one enthusiastic manual inventory, and never open it again.
Barcode scanning changes the number to about four minutes, and four minutes is survivable.
Three routes exist. The Grocy Android app (grocy-android, by Patrick Zedler) uses the phone camera and is genuinely good — scan, quantity, done, with the app remembering the product after its first sighting. The built-in web scanner works in a browser on a phone and is slower. And Barcode Buddy is a companion service that accepts input from a cheap USB barcode scanner — the £15 kind that behaves as a keyboard — and pushes to Grocy’s API.
| |
Generate the API key in Grocy under Settings → Manage API keys. Verify the two are talking before you buy a scanner:
| |
Barcode Buddy also queries Open Food Facts for products it has never seen, so a new barcode arrives with a name attached rather than as a number you have to identify. The lookup quality is uneven — Danish supermarket own-brands are frequently absent — and it saves enough typing to be worth it.
My setup is the USB scanner on a hook by the door. The shopping comes in, gets scanned onto the counter as it is put away, and the whole thing costs the time it takes to unpack anyway. That is the only configuration I have found that survives contact with a real household.
The consumption problem, which nobody solves
Getting stock in is solved. Getting stock out is where Grocy meets reality and reality wins.
To keep the numbers true, every act of eating must be recorded. You have some cheese: tell Grocy. Your partner makes a sandwich: they must tell Grocy. A guest has a beer: someone tells Grocy. Nobody tells Grocy. Within a fortnight your stock says you have 400g of cheese and the fridge says otherwise, and the moment the numbers are wrong, every downstream feature — the shopping list, the recipe stock check, the expiry warnings — becomes actively misleading.
Three mitigations genuinely help, and none of them fix it.
Consume via recipes. If you cook from a recipe in Grocy, one button consumes every ingredient at once. This is the single highest-leverage habit, and it is also why people try to make Grocy their recipe manager, at which point they discover its recipe module is competent and joyless. I keep recipes in Mealie, which is a better tool for the reading-and-cooking part, and accept the disconnect — the case for that split is in Mealie: Recipes You Actually Own.
Track only what matters. This is the one that saved it for me. I do not track the fridge. I track the pantry: flour, rice, tinned tomatoes, coffee, pasta, the twelve things whose absence ruins a Tuesday. Twelve slow-moving products with long shelf lives and a minimum stock amount each. The consumption events are rare, memorable, and happen at a moment when I am already annoyed enough to open my phone.
Automate the entry point. A scanner by the bin for the empty packet is the classic trick. It works better than it sounds and it still relies on a human.
Grocy’s own documentation is upfront that this is the hard part, which I respect enormously. The failure is inherent to inventory systems everywhere, including the ones running actual warehouses, which is why actual warehouses have staff whose entire job is the count.
Chores, the module that quietly outperforms
Everything above is about food, and food is the part of Grocy that struggles. The chores module has no such problem, and after two years it is the reason the container is still running.
A chore is a recurring household task with a schedule, an assignee and a record of when it was last done. Descale the kettle every three months. Clean the extractor filter every six weeks. Bleed the radiators every autumn. Change the water filter every 400 litres — Grocy handles usage-based schedules as well as calendar ones.
The reason this works where stock tracking fails is the input frequency. Stock demands a data-entry event every time anyone eats; chores demand one every few weeks, at the exact moment you have just finished the task and feel pleased with yourself. The cost lands when motivation is highest. That is the whole difference, and it explains why the same household that abandons the fridge inventory in a fortnight will happily maintain a chore list for years.
Two configuration details make it stick. Set the tracking to “track date only” for anything where the schedule should reset from completion rather than run on a fixed calendar — otherwise a chore done late generates an immediate second due date, which is demoralising and wrong. And export the calendar:
| |
That iCal feed subscribes into any calendar app, which means the chores appear where you already look instead of in a website you have to remember to open. Grocy also exposes a token-authenticated URL for the same feed under Settings → Calendar, so a phone can subscribe without holding an API key.
The equipment module deserves a sentence too. It stores a PDF against an appliance, and that is all it does. When the dishwasher throws an error code at 22:00 on a Sunday, the manual is two taps away rather than in a drawer, in a language, behind the warranty card. It has paid for itself three times.
Troubleshooting
Permission denied writing the database. PUID/PGID must own /srv/appdata/grocy/config. Grocy writes constantly, so a read-only volume produces a site that renders and silently refuses every change:
| |
Dates display in the wrong format and expiry warnings look mad. Grocy’s locale is per-user under Settings → User settings, separate from the TZ env var. Both need setting; the container’s timezone alone does nothing for the display format.
Barcode Buddy sees the scanner but nothing reaches Grocy. The API key, or the URL. BBUDDY_API_URL must end in /api/ with the trailing slash, and both containers must share a network. Check from inside:
| |
Stock numbers drift into nonsense. Do an inventory correction rather than fighting it. Grocy has a proper “inventory” transaction that sets the true amount and books the difference, which is the same thing a real warehouse does at stocktake. Doing this quarterly is normal and expected.
An upgrade changed the database and you want to go back. You cannot. Grocy migrates the SQLite schema forward on start and there is no downgrade path. Back up before every version bump.
Backups
The easiest backup story of anything I run, provided you use the right tool for SQLite:
| |
.backup takes a consistent snapshot of a live database; copying the file with cp while Grocy is writing gives you a corrupt file that looks fine until you need it. That distinction has caught me out before and I keep repeating it because it keeps catching people out. Sweep the result offsite with whatever you already run — mine is the arrangement from Borg vs Restic: Painless Encrypted Backups.
Grocy also has a full database export from the UI, plus per-entity CSV. The CSV is the artefact that will still be readable when Grocy is a memory.
The verdict
Grocy is excellent software aimed at a problem that resists software. The engineering is careful, the data model is properly thought through, the SQLite-only architecture is a joy, and the maintainer has kept it coherent and unbloated for years. There is nothing wrong with it.
It will still probably fail in your house, and it will fail for the reason every inventory system fails: the count depends on people, and people are eating your data model.
Run it if you will buy a barcode scanner in the first week, you will restrict tracking to a dozen slow-moving pantry staples, and you have a household of one or two disciplined adults. Under those conditions it is quietly brilliant, the shopping list generates itself, and you stop discovering there is no coffee at 7am on a Monday.
Skip it if you are picturing a fully accurate fridge. That is not achievable, and chasing it will cost you a month and end with an uninstall. Self-hosting has an ongoing human cost that the install guide never mentions, which is the whole argument of Self-Hosting Is Not Free: Accounting for Your Own Time, and Grocy charges that cost every single day at the kitchen counter.
Two years in, I track eleven products, three chores and one boiler manual. That sliver of Grocy has earned its 120MB many times over. The other ninety per cent of the application is superb, and I have switched it off.




