The previous lesson's plain file element hands you a raw, temporary upload and leaves the saving to you. managed_file is the version most real Drupal modules actually use — it wraps that same mechanism with automatic AJAX saving, a live preview, and a remove button, turning file uploads from a manual chore into a couple of array keys.
What you'll learn in this lesson
- The
managed_filedefinition and where it stores files by default - How the submitted value differs from a plain
fileelement — you get a file ID, not raw upload data - Marking an uploaded file permanent so it survives Drupal's automatic cleanup
A basic managed_file element
$form['photo'] = [
'#type' => 'managed_file',
'#title' => $this->t('Profile photo'),
'#upload_location' => 'public://profile-photos/',
'#upload_validators' => [
'file_validate_extensions' => ['png jpg jpeg'],
'file_validate_size' => [2 * 1024 * 1024],
],
];
#upload_location tells Drupal exactly where to save the file — public:// resolves to your site's public files directory, and the AJAX-driven save happens automatically the moment the user selects a file, well before the surrounding form is even submitted.
The submitted value: a file ID, not raw data
$form_state->getValue('photo') returns an array of file entity IDs (fids) — typically one, unless you've set #multiple. Load the actual managed File entity from that ID whenever you need its real properties:
$fids = $form_state->getValue('photo');
if (!empty($fids)) {
$file = \Drupal\file\Entity\File::load(reset($fids));
}
Making the file permanent
Here's the detail that trips people up the first time: a freshly uploaded managed file starts life as temporary, and Drupal's own cron job deletes unreferenced temporary files after a set period (24 hours by default). If your submit handler doesn't explicitly attach the file somewhere permanent, the upload can vanish before anyone notices.
$file->setPermanent();
$file->save();
Saving the file's ID onto a content entity's file/image field (rather than a plain config value) usually marks it permanent for you automatically, via Drupal's file usage tracking — but if you're storing the fid somewhere else entirely (like a config object), call setPermanent() yourself or the file will quietly disappear.
managed_file/permanent-marking pattern under the hood, via the platform's content-import API.Quick check: a user uploads a file via
managed_file, but your submit handler saves the fid into a plain config value rather than a content entity's file field, and never callssetPermanent(). What happens to the file within a day? (It gets deleted by Drupal's own cron cleanup — an uploaded managed file starts temporary, and nothing marked it permanent, so the automatic garbage collection removes it.)
Key takeaways
managed_filesaves the upload automatically via AJAX, well before the form is even submitted — you get back a file ID, not raw upload data.- A newly uploaded file starts temporary and is deleted by cron within a set window unless something marks it permanent.
- Attaching a file's ID to a content entity's file field typically marks it permanent automatically via file usage tracking; anywhere else, call
setPermanent()yourself.
Coming up next
You've now covered file uploads end to end. Next, we look at referencing other content entirely — the entity autocomplete/reference field.