Introduction
Binary fields are not glamorous, but they are everywhere in a real Odoo implementation. Every time a user uploads a signed contract, attaches a product datasheet, or stores a company logo on a record, there is a Binary field working behind the scenes. Understanding how it stores data, where that data ends up, and when to use a different field type makes a real difference when you are building custom forms or extending Odoo models.
This guide covers what the Binary field stores, how attachment mode affects storage and performance, how to create and customize it using Odoo Studio or Python, and practical business use cases across CRM, HR, Inventory, and more.
What is the Binary Field in Odoo
In the Odoo ORM, the Binary field (fields.Binary) stores raw binary data: files, documents, images, or any content a user uploads to a record. From the user perspective, it appears as a file upload button in form views. Once a file is attached, the same button lets users download it with a single click.
The most important technical detail is where that data actually ends up. By default in modern Odoo versions, Binary fields use attachment mode. This means the file content is stored in the ir.attachment table and on the server filestore, not directly inside the model column. The model column holds only a reference ID pointing to the attachment record. This approach keeps your main database tables lean and lets Odoo manage files efficiently.
In Odoo Studio, the Binary field is labeled File in the field picker. It renders as a simple upload and download control in form views. For image content specifically, Odoo also provides a dedicated fields.Image type that adds automatic resizing and thumbnail preview. We will cover that in the relevant sections below.
Here is how a Binary field looks in a Python model definition:
from odoo import fields, models
class ResPartner(models.Model):
_inherit = 'res.partner'
x_signed_contract = fields.Binary(
string='Signed Contract',
attachment=True,
)
x_signed_contract_filename = fields.Char(
string='Signed Contract Filename',
)
Note the companion x_signed_contract_filename Char field. Pairing a Binary field with a Char field for the filename is a standard Odoo development pattern. Odoo uses the _filename field to remember and display the original file name in the interface. Without it, downloaded files may get a generic name.
How the Field Works
When you define a Binary field in the Odoo data model, the framework handles the column creation automatically at module install or upgrade. No manual SQL is needed on your side.
Storage Modes
The attachment parameter on a Binary field controls where the file bytes are actually stored:
- attachment=True (recommended): File content is stored in
ir.attachment, linked to the record by model name and record ID. The model column holds only a reference ID. This keeps model tables small and leverages Odoo's filestore system. - attachment=False: The raw base64-encoded data is stored directly inside the model's database column. This causes tables to grow very large, slowing down queries across the entire model. Avoid this mode for anything larger than a small image thumbnail.
Data Format
Binary fields store and return data as base64-encoded bytes. When you read a Binary field via the Odoo ORM or the XML-RPC API, you receive a base64 string. When you write to it, you must also provide a base64-encoded string.
In practice, this means encoding before writing and decoding after reading:
import base64
# Writing a file to a Binary field
with open('document.pdf', 'rb') as f:
encoded = base64.b64encode(f.read()).decode('utf-8')
record.write({'x_signed_contract': encoded})
# Reading a file from a Binary field
raw_bytes = base64.b64decode(record.x_signed_contract)
Key Field Attributes
These are the most important attributes you can configure on a Binary field in the Odoo framework:
- attachment: Boolean. Whether to store in
ir.attachment(True) or directly in the column (False). Default: True in recent Odoo versions. - string: Display label shown in the interface.
- required: Makes the field mandatory before saving the record.
- compute: Links a Python method to compute the field value dynamically, for example generating a PDF on the fly as an odoo computed field.
- store: When used with
compute, saves the computed value to the database. - groups: Restricts field access to specific Odoo user groups. Important for sensitive documents.
- copy: Controls whether the value is duplicated when a record is copied. Defaults vary depending on attachment mode and Odoo version.
The fields.Image Subclass
fields.Image is a specialized subclass of fields.Binary introduced in Odoo 13. It adds automatic image resizing to a configurable maximum dimension, an optional preview size for thumbnails, and renders a proper image preview in form views. For storing product images, partner photos, company logos, or any visual content, use fields.Image rather than a plain Binary field. It prevents excessively large uploads and provides a much better user experience for image data.
How It Appears in Views
In form views, the default widget for a Binary field is an upload and download button. For image content, apply the image widget to get a thumbnail preview instead. In list views, Binary fields are usually not shown directly because loading full file content for every visible row creates unnecessary data transfer. The standard approach is to show a boolean indicator or an icon in list views to signal whether a file is attached.
Business Use Cases
The Binary field appears across many Odoo modules in real implementations. Here are five practical examples from common business workflows.
CRM: Storing Signed NDAs or Contracts on Customer Records
Many companies need to attach a signed document directly to a customer or lead record in Odoo CRM. A Binary field on res.partner or crm.lead gives sales teams one-click access to the relevant contract without leaving the Odoo interface. This eliminates the need for a separate document management tool for basic file storage, and it keeps the information exactly where the team expects to find it during the sales process.
HR: Employee Document Storage
HR departments regularly need to store copies of employee ID documents, work permits, signed employment contracts, or training certificates. A Binary field on hr.employee stores these files securely within Odoo's access control system. Using the groups attribute, you can restrict visibility so only HR managers can view sensitive documents, while other managers see the form without accessing the actual files. This is a common Odoo customization request in companies with strict data privacy requirements.
Inventory: Product Specification Sheets and Safety Data
Technical products often come with PDF specification sheets, safety data sheets, or quality certificates from the manufacturer. A Binary field on product.template lets procurement teams and warehouse staff access the right documentation directly from the product record in Odoo. This is one of the most frequently requested Odoo customization additions in manufacturing and distribution companies, and it is straightforward to implement with either Odoo Studio or a custom Python module.
Sales: Company Stamp or Authorized Signature Image
Some business contexts require a company stamp or an authorized signature on printed quotations or order confirmations. A fields.Image field on res.company stores this visual asset, which can then be referenced in a QWeb report template. This allows printed documents to include the stamp automatically without any manual handling per document, saving time in high-volume sales operations and reducing the risk of sending unsigned quotes by accident.
Accounting: Scanned Receipt Attachment on Expense Records
Expense management workflows typically require attaching a scanned receipt or invoice to each expense record as proof for reimbursement. For standard Odoo expenses, the attachment system handles this natively. But on custom expense models, vendor bill workflows, or third-party integrations, a Binary field provides a clean way to store the receipt image or PDF directly on the record and include it in approval routing logic without relying on the generic attachment panel.
Creating or Customizing the Binary Field
There are three main ways to add a Binary field to an Odoo model, depending on your technical context and how much control you need.
Using Odoo Studio (No Code)
Odoo Studio is the built-in low-code customization tool. To add a Binary field without writing any code:
- Open Odoo Studio from the main menu.
- Navigate to the form where you want the field.
- Drag a File field from the field picker onto the form.
- Set the label and any optional visibility conditions in the properties panel.
- Save and close Studio.
Studio creates the field with an x_studio_ prefix and automatically uses attachment mode. No database configuration needed on your side. This is one of the most accessible Odoo studio fields for business users who need file upload capability on their forms without developer involvement.
Using Python in a Custom Module
For Odoo development that needs to be version-controlled and deployed across multiple environments, the standard approach is to define Binary fields directly in Python. This is the recommended approach in any Odoo developer guide for serious Odoo customization work:
from odoo import fields, models
class HrEmployee(models.Model):
_inherit = 'hr.employee'
x_id_document = fields.Binary(
string='ID Document',
attachment=True,
groups='hr.group_hr_user',
)
x_id_document_filename = fields.Char(
string='ID Document Filename',
)
After adding the field to the model, include it in the form view XML with the binary widget and the filename attribute pointing to the companion Char field. Odoo handles the database column automatically on module install or upgrade. This approach works cleanly across all Odoo deployment types including Odoo.sh and on-premise installations.
Using the XML-RPC API
If you are managing Odoo field creation programmatically, for example through a remote configuration script or a deployment notebook, you can create Binary fields via the XML-RPC API:
field_id = models.execute_kw(
ODOO_DB, uid, ODOO_API_KEY,
'ir.model.fields', 'create',
[{
'name': 'x_custom_document',
'field_description': 'Custom Document',
'model_id': model_id,
'ttype': 'binary',
'state': 'manual',
}]
)
The state: manual value tells Odoo this field was created manually rather than installed by a module. Fields created via the API use attachment mode by default in current Odoo versions. This is the approach used in automated Odoo configuration scripts and remote deployment workflows.
Best Practices
1. Always use attachment=True
Unless you have a very specific technical reason to store file content directly in the database column, use attachment mode. It keeps model tables small, prevents slow queries, and lets Odoo manage files through its built-in filestore. This is also the default behavior in recent versions, so simply omitting the attachment parameter is enough in most cases. For any file larger than a small thumbnail, attachment mode is not optional.
2. Pair Binary fields with a filename Char field
Always add a companion _filename Char field alongside any Binary field used in a form view. Without it, the file upload widget cannot display or restore the original filename, and users who download the file end up with a generic name like download. This small addition takes one line of code and makes a noticeable difference to the user experience of the form.
3. Use fields.Image for visual content
If you are storing product photos, partner portraits, company logos, or any other images, use fields.Image instead of a plain Binary field. It automatically limits upload size to the configured maximum dimensions, renders a thumbnail in the interface, and includes a separate field for the resized preview image. Using the right field type for the right content is a core principle in clean Odoo data model design.
4. Restrict access with the groups parameter
Binary fields that store sensitive documents such as employee files, signed contracts, or financial records should define access restrictions using the groups parameter. This limits who can read or write the field, which matters both for data privacy and for audit trail requirements in regulated environments.
5. Handle base64 encoding carefully in code
When reading or writing Binary fields programmatically, always handle the base64 encoding explicitly. Use base64.b64encode(file_bytes).decode('utf-8') to convert bytes before writing, and base64.b64decode(field_value) to convert back to bytes after reading. Do not assume the data is already in the format you need. This is a common source of bugs in Odoo ORM integrations that only surface when real files are processed.
Common Pitfalls
Setting attachment=False for large files
Storing file content directly in a database column can bloat your PostgreSQL tables significantly. A few dozen PDF documents stored with attachment=False can add hundreds of megabytes to a single model table, slowing down every query on that model. This is one of the most impactful configuration mistakes in Odoo database management. Once data is stored this way and the table grows large, migrating to attachment mode requires a custom script and careful planning.
Forgetting the filename companion field
Without a paired Char field for the filename, users who download a file from a Binary field often get a generic filename. This is a small but persistent problem that makes the implementation feel unfinished. Adding the companion field takes less than a minute and should be part of any Binary field definition that appears in a user-facing form view.
Confusing Binary and Image fields
Using a plain Binary field for image content misses the automatic resizing and thumbnail rendering that fields.Image provides. Users can upload very large image files that slow down form loads and consume unnecessary storage space. Conversely, using fields.Image for non-image files like PDFs causes errors because Odoo tries to process the content as an image. The rule is simple: match the field type to the expected content type.
Including Binary fields directly in list views
Adding a Binary field to a list view causes Odoo to load the full file content for every visible row. For a list with fifty records, this can mean transferring megabytes of data just to render the page. If you need to indicate file presence in a list view, use a computed boolean field or an icon button instead of the Binary field directly. This is a common performance issue in Odoo implementations that only becomes visible at real data volumes.
Not checking for False before processing in code
A Binary field without a value returns False in Python, not an empty string and not empty bytes. If you try to decode a Binary field value without checking for False first, you get a TypeError that crashes the method. Always guard with: if record.x_document: data = base64.b64decode(record.x_document). This matters in compute methods, server actions, and any code that processes Binary values conditionally.
Conclusion
The Binary field is a straightforward but important part of the Odoo data model. It handles file and document storage in a way that integrates naturally with Odoo's interface, its attachment system, and its access control framework.
The main habits to develop: always use attachment mode, pair Binary fields with a filename Char field, choose fields.Image for visual content, restrict access for sensitive documents, and handle base64 encoding carefully in custom code. These practices prevent the most common issues before they have a chance to surface in production.
Whether you are adding a file upload field through Odoo Studio, building a custom Python module, or managing field creation via the Odoo ORM or XML-RPC API, getting Binary fields right from the start leads to a cleaner and more reliable Odoo implementation overall.
At Dasolo, we help companies implement, customize, and optimize Odoo across all departments. Whether you need help designing a data model with the right field types, building custom file management workflows, or developing a full Odoo module, our team is here to support you. Reach out to us and let's talk about your Odoo project.