Skip to main content
iVentureTeam

project

On an Odoo task form the project field is not a plain dropdown: the project widget wraps the standard many2one and shows a gray Private placeholder when the task belongs to nobody's project. Small widget, one hardcoded assumption worth knowing.

Siddharth JambukiyaSiddharth JambukiyaOdoo Techno-Functional Consultant
August 20, 2026Updated August 20, 20265 min read
Technical nameproject
Field typesmany2one
Viewsform, list
Moduleproject
Used in core5 occurrences across 1 module: project (task form and task list views)
VersionsOdoo 20.0, Odoo 19.0, Odoo 18.0, Odoo 17.0
No-code setupNo. Studio offers the generic Many2one; this project variant is applied in XML.
Alternativesmany2one, res_partner_many2one, so_line_field

What the Project field widget does

The project widget is a thin fork of the standard many2one that the project module applies to the project field on tasks. Functionally it is a normal relational picker: autocomplete, quick create, internal link, everything the base widget does.

Its whole reason to exist is the empty state. Odoo 17 introduced private tasks, tasks that live outside any project, and the UI needed to say so. When the record's project_id is empty and the field is not required in the current view, the widget injects a Private placeholder and a private_placeholder CSS class that styles it gray with a lock connotation. It also forces the input to full width with a hardcoded w-100 class.

One subtlety from the source: the emptiness check reads record.data.project_id and record._isRequired("project_id") by literal field name. Put this widget on a many2one named anything else and the placeholder logic silently follows the record's project_id field, not the field you attached it to.

What this means for your team

For teams that use personal to do lists inside Odoo, this placeholder is the difference between a task that looks broken (empty required looking field) and a task that clearly says it is private. Nobody files a support ticket about an empty project field when it reads Private.

For implementers the widget is a reminder that task privacy is a first class state in modern Odoo. Workflows that assume every task has a project (billing rollups, stage automations) need an explicit rule for private tasks, and this little gray label is where users will first notice the concept exists.

Supported options in Odoo 19

The widget declares no options of its own. Because it is registered through buildM2OFieldDescription, it inherits the full many2one option set. The table lists the inherited options as declared in many2one_field.js in 19.0, plus the two undocumented ones only visible in extractM2OFieldProps.

OptionTypeWhat it does
no_openbooleanInherited from many2one. Removes the internal link so clicking the value in readonly does not open the project form. Odoo core uses it on the task list view of this very widget.(default: false)
no_createbooleanInherited from many2one. Hides both quick create and Create and Edit in the autocomplete, so users can only pick existing projects.(default: false)
no_quick_createbooleanInherited from many2one. Hides only the inline Create "x" entry; Create and Edit stays available.(default: false)
no_create_editbooleanInherited from many2one. Hides the Create and Edit dialog entry; quick create stays available.(default: false)
search_thresholdintegerInherited from many2one, new in 19. The dropdown only starts searching once the user has typed this many characters, useful on databases with thousands of projects.(since Odoo 19.0)
placeholder_fieldfield nameInherited from many2one, new in 19. Reads the placeholder text from another field on the record. The widget's own Private placeholder takes over when project_id is empty and not required.(since Odoo 19.0)
can_scan_barcodebooleanUndocumented, inherited from many2one: read in extractM2OFieldProps but never declared. Enables barcode based selection on mobile.(default: false)
create_name_fieldfield nameUndocumented, inherited from many2one: read in extractM2OFieldProps but never declared. Sets which field receives the typed text when quick creating a record.

All options below are inherited from the standard many2one. The two marked undocumented are read in extractM2OFieldProps but never declared in supportedOptions, so no Studio UI will ever show them.

Working examples

The task form usage from project_task_views.xml, where required is conditional and drives the placeholder:

<field name="project_id"
       required="parent_id or child_ids or is_template"
       widget="project"/>

The task list usage, combining the widget with an inherited many2one option:

<field name="project_id" string="Project" optional="hide"
       required="1" options="{'no_open': 1}" widget="project"/>

Note that with required="1" the Private placeholder never appears: the widget only shows it when the field is allowed to stay empty.

From display_in_project to Private: the widget's history

The widget looked quite different in Odoo 17, and the history explains some behavior you may remember:

17.0: the placeholder appeared when both project_id and parent_id were empty, the displayed name was blanked when a task had a project but display_in_project was false, and picking a project auto set display_in_project to true through an extra updateRecord override.

18.0: all the display_in_project logic was dropped. The check became what it still is in 19: empty project_id plus not required in this view.

19.0: same behavior, rebuilt on the new computeM2OProps composition pattern (a plain component wrapping the Many2One component instead of subclassing the field), and the forced w-100 class arrived.

Because required ness is evaluated per view (record._isRequired), the same empty task can show Private on one form and a normal empty input on another where the field is required. That is intentional, not a bug.

Version compatibility

VersionStatusNotes
Odoo 20.0In developmentNot released. Adds template task awareness (All Projects placeholder) in the development branch; see below.
Odoo 19.0VerifiedVerified against the shipped source and tested on a clean database.
Odoo 18.0VerifiedSame Private placeholder logic; older subclass based implementation.
Odoo 17.0Partial / changedWidget exists but with different logic: parent_id check, display_in_project auto write, hidden display names.
Odoo 16.0Not availableThe widget does not exist in 16.0; task views use the plain many2one.

No XML changes are needed between 17, 18 and 19. If you relied on the 17 behavior of auto setting display_in_project, that write disappeared in 18 and needs an explicit onchange or automation instead.

What is changing in Odoo 20

Odoo 20 is expected at Odoo Experience in Brussels, 24 to 26 September 2026. The changes below are read from the public development branch and are not final until release.

Template tasks get their own placeholder. Master adds is_template to the widget's related fields and branches the empty state: a normal task still shows Private, while a template task shows All Projects instead. Two label getters (a lock prefixed Private and All Projects) appear alongside.

The many2one composition itself moves to the shared many2OneFieldProps export as part of the framework wide props migration, with no option changes. We will re verify this page against the released branch after the launch.

Common problems and fixes

SymptomCause and fix
The Private placeholder never showsThe field is required in this view; the widget only shows Private when project_id may stay empty. Check the required attribute or expression on the field in the current view.
Widget applied to another many2one shows odd placeholder behaviorThe source reads record.data.project_id by literal name, regardless of which field carries the widget. Only use widget="project" on fields named project_id; fork the widget for other fields.
After migrating from 17, display_in_project no longer updates on project changeThe 17 widget auto set display_in_project to true; 18 removed that write. Add an onchange or automation rule if your customization depended on it.
The picker searches on the first keystroke and feels slowNo typeahead threshold is set; the widget queries immediately like any many2one. On Odoo 19, add options="{'search_threshold': 3}".

Project field widget vs the alternatives

WidgetBest forKey difference
projectThe project field on tasks, with a clear Private empty stateStandard many2one plus a Private placeholder tied to the project_id field name
many2oneAny relational field without task privacy semanticsNo Private placeholder, no forced full width
res_partner_many2onePartner fields with company autocompleteAdds IAP powered company suggestions instead of an empty state label
so_line_fieldSale order line links on timesheetsFlags edited lines through an is_so_line_edited companion field

Use project only on task project fields where the private state matters. Anywhere else, the standard many2one or one of its specialized forks is the honest choice.

Frequently asked questions

What does the project widget do in Odoo?+
It is the many2one picker used for the project field on tasks. Its single extra behavior is showing a gray Private placeholder when the task has no project and the field is not required, signaling a private task.
Why does my task's project field say Private?+
The task is not linked to any project, which Odoo treats as a private task visible mainly to its assignees. Pick a project to make it a regular project task.
Can I use the project widget on my own many2one field?+
Technically yes, but the placeholder logic reads the record's project_id field by hardcoded name, not the field the widget sits on. On any other field the behavior will be misleading; fork the component instead.
Does the project widget support standard many2one options?+
Yes. It is built with buildM2OFieldDescription, so no_open, no_create, no_quick_create, no_create_edit and the 19.0 additions search_threshold and placeholder_field all work. Odoo itself passes no_open on the task list.
What changes for this widget in Odoo 20?+
The development branch adds is_template awareness: template tasks show an All Projects placeholder instead of Private. Not final until the September 2026 release.

Tasks, projects and privacy rules that behave

Private tasks, template tasks, portal visibility: Odoo project setups fail in the details. We configure and extend Odoo project for teams from 5 to 500 users, including custom pickers and automations around project_id.

Plan my Odoo project setup

How this page was produced

This page was verified by reading the Odoo 19.0 project module source (project_many2one_field.js) and the inherited option declarations in many2one_field.js of the web module, then diffing the widget file across the 17.0 and 18.0 branches and the public development branch for the Odoo 20 section. The placeholder behavior was confirmed on a clean Odoo 19 database against Odoo's own task views. Report corrections via our contact page.