Skip links

Odoo Database Structure Explained

Why a business owner should care

You do not need to write SQL. But three decisions depend on understanding roughly how Odoo stores data:

Whether your data is portable. Can you get it out if you ever leave?

Why some changes are blocked. Odoo refuses certain edits, and the reason is structural rather than arbitrary.

Why reports can be trusted. Or not.

This article covers the shape of it, without the technical detail.

One database, standard format

Odoo stores everything in PostgreSQL — a standard, widely used, open-source database.

Three consequences that matter commercially.

No proprietary format. Your data is not locked in an encrypted file only the vendor can open. A backup can be read with standard tools.

Portable. You can host it on Odoo’s cloud, on your own server, or move between them.

Yours if you leave. Compare that with systems where getting your own history out requires a paid export service and a three-month wait.

One thing to know: attachments and images are not in the database. They live in a separate filestore on disk. A backup needs both — a database backup alone restores your invoices with every attachment missing.

FIGURE 1: WHAT A COMPLETE BACKUP CONTAINS

The database

  • Customers, products, orders
  • Stock moves and journal entries
  • Settings and user accounts
  • Standard PostgreSQL format

The filestore

  • Attachments and uploaded documents
  • Product images
  • Report PDFs that were saved
  • Separate files on disk

Models and records

Odoo organises data into models. A model is a type of thing — a customer, a product, a sales order, a journal entry.

Each model has fields — the pieces of information it holds. A customer has a name, an address, a payment term.

Each individual entry is a record.

That is the whole vocabulary. When somebody says “the sale.order model”, they mean the sales order table.

Relationships

This is the part that explains a lot of Odoo’s behaviour.

Records are linked to each other. A sales order links to a customer, to a price list, to order lines, to deliveries, to invoices.

Those links are why deleting is often blocked.

If a customer has invoices, Odoo will not let you delete the customer — the invoices would point at nothing, and your accounts would break.

This is a protection, not an obstacle. The right answer is almost always to archive rather than delete. Archiving removes the record from normal views and keeps every link intact.

A useful rule: archive by default, delete almost never.

FIGURE 2: THREE THINGS THE STRUCTURE EXPLAINS

Why deleting is blocked

  • Records are linked. Deleting one would leave others pointing at nothing.

Why archiving exists

  • It hides the record and keeps every link. Almost always what you actually want.

Why some changes are refused

  • A product’s unit of measure is embedded in every past transaction.

Why some changes are refused

Two examples that come up constantly, and both make sense once you see the structure.

Unit of measure on a product. Once a product has stock moves and order lines, its unit is embedded in all of them. Changing it would make every historical record wrong. Odoo blocks it.

Editing a posted invoice. It has a sequence number and journal entries. Changing it silently would break your audit trail. You issue a credit note instead.

Neither is Odoo being awkward. Both protect the integrity of data other records depend on.

The practical lesson: get units of measure and your chart of accounts right before you start, because those are the decisions the structure makes permanent.

Where your business data lives

A rough map, useful when somebody asks where something is stored.

Partners. Customers, suppliers and contacts are all the same model, distinguished by flags. One company appearing as both a customer and a supplier is one record, not two.

Products. Split into templates and variants. A shirt is a template; each size and colour is a variant with its own stock.

Stock. Quants hold current quantity by location. Moves hold the history of every change.

Accounting. Journal entries, each with lines that must balance. Odoo enforces that at the database level.

Documents. Sales orders, purchase orders, invoices — each a header record with line records attached.

Custom fields and modules

When a developer adds a field, it becomes a real column in the database, defined by the module that added it.

Why that matters:

Uninstalling the module removes the field and its data. Never uninstall a custom module on a live system without understanding what it holds.

Version upgrades touch the structure. Fields get renamed, models get restructured. Custom modules built against the old structure need checking.

Studio changes are also structural. They create fields too, with less visibility over what was added and why.

Backups, practically

Three things, and the third is the one people skip.

Back up both parts. Database and filestore.

Store a copy off the server. A backup on the same machine does not survive the machine failing or being encrypted.

Test a restore quarterly. Restore into a separate database. Open it. Check a recent invoice, an attachment and a stock figure.

An untested backup is not a backup. The number of companies who discover theirs have been silently failing — at the moment they need one — is not small.

FIGURE 3: WHAT THE STRUCTURE MEANS IN PRACTICE

Your data is portable

  • Standard PostgreSQL. No proprietary format, no vendor lock.

Archive, do not delete

  • Links protect your history. Archiving is almost always the right answer.

Get units and accounts right early

  • Both become effectively permanent once you have transactions.

Back up both parts, and test it

  • Database plus filestore, stored off the server, restored quarterly.

What this means for you

Four practical positions.

Your data is not trapped. That is a genuine advantage over many alternatives, and it is worth knowing.

Archive instead of deleting. Safe, reversible, and it keeps your history intact.

Decide units of measure and chart of accounts before go-live. The structure makes them expensive to change afterwards.

Test your backups. Both parts, off the server, restored properly, at least quarterly.

What you do not need to worry about

Writing queries. Odoo’s reporting reads the same data and applies your permission rules. Direct database access bypasses those rules and is rarely necessary.

Table names. Unless you are commissioning an integration, and then your developer handles it.

Optimising it. Routine database maintenance is a server administration task, and it is an argument for hosted Odoo if nobody in your company does it.

The short version

Odoo stores everything in one standard PostgreSQL database, plus a filestore for attachments.

Records are linked, which is why deleting is often blocked and archiving is the right answer.

Some things become permanent once you have transactions — units of measure and your chart of accounts especially. Decide those early.

And back up both parts, off the server, and actually test a restore.

Not sure whether your backups would actually restore?

Get in touch. We will check that both the database and the filestore are covered, and restore one to prove it.

Leave a comment

Drag