diff --git a/package_manager/package_manager.services.yml b/package_manager/package_manager.services.yml
index 41deacfbde761f9c6cb50b730007058019e8b93a..c083562388f8c7457bf535bd204b9610e93d6fa8 100644
--- a/package_manager/package_manager.services.yml
+++ b/package_manager/package_manager.services.yml
@@ -94,3 +94,4 @@ services:
       - '@package_manager.stager'
       - '@package_manager.committer'
       - '@package_manager.cleaner'
+      - '@event_dispatcher'
diff --git a/package_manager/src/Event/PostApplyEvent.php b/package_manager/src/Event/PostApplyEvent.php
new file mode 100644
index 0000000000000000000000000000000000000000..d2a9693cf9c3ee99970538fdbf404564c80309ac
--- /dev/null
+++ b/package_manager/src/Event/PostApplyEvent.php
@@ -0,0 +1,9 @@
+<?php
+
+namespace Drupal\package_manager\Event;
+
+/**
+ * Event fired after staged changes are synced to the active directory.
+ */
+class PostApplyEvent extends StageEvent {
+}
diff --git a/package_manager/src/Event/PostCreateEvent.php b/package_manager/src/Event/PostCreateEvent.php
new file mode 100644
index 0000000000000000000000000000000000000000..104bc78ad6ff0681c83ad3f494ee8e309c87f7e9
--- /dev/null
+++ b/package_manager/src/Event/PostCreateEvent.php
@@ -0,0 +1,9 @@
+<?php
+
+namespace Drupal\package_manager\Event;
+
+/**
+ * Event fired after a staging area has been created.
+ */
+class PostCreateEvent extends StageEvent {
+}
diff --git a/package_manager/src/Event/PostDestroyEvent.php b/package_manager/src/Event/PostDestroyEvent.php
new file mode 100644
index 0000000000000000000000000000000000000000..3388a988e126da919dfbc598946910f38b86cbbe
--- /dev/null
+++ b/package_manager/src/Event/PostDestroyEvent.php
@@ -0,0 +1,9 @@
+<?php
+
+namespace Drupal\package_manager\Event;
+
+/**
+ * Event fired after the staging area is destroyed.
+ */
+class PostDestroyEvent extends StageEvent {
+}
diff --git a/package_manager/src/Event/PostRequireEvent.php b/package_manager/src/Event/PostRequireEvent.php
new file mode 100644
index 0000000000000000000000000000000000000000..55b4184dd3d96daaeeba55317c227fd0bbfb089c
--- /dev/null
+++ b/package_manager/src/Event/PostRequireEvent.php
@@ -0,0 +1,9 @@
+<?php
+
+namespace Drupal\package_manager\Event;
+
+/**
+ * Event fired after packages are added to the staging area.
+ */
+class PostRequireEvent extends StageEvent {
+}
diff --git a/package_manager/src/Event/PreApplyEvent.php b/package_manager/src/Event/PreApplyEvent.php
new file mode 100644
index 0000000000000000000000000000000000000000..3ffdf0d17594bb85403174ac591dbd65e956574d
--- /dev/null
+++ b/package_manager/src/Event/PreApplyEvent.php
@@ -0,0 +1,9 @@
+<?php
+
+namespace Drupal\package_manager\Event;
+
+/**
+ * Event fired before staged changes are synced to the active directory.
+ */
+class PreApplyEvent extends StageEvent {
+}
diff --git a/package_manager/src/Event/PreCreateEvent.php b/package_manager/src/Event/PreCreateEvent.php
new file mode 100644
index 0000000000000000000000000000000000000000..c893738beef1abef37d6899df2720f9f25f937f2
--- /dev/null
+++ b/package_manager/src/Event/PreCreateEvent.php
@@ -0,0 +1,9 @@
+<?php
+
+namespace Drupal\package_manager\Event;
+
+/**
+ * Event fired before a staging area is created.
+ */
+class PreCreateEvent extends StageEvent {
+}
diff --git a/package_manager/src/Event/PreDestroyEvent.php b/package_manager/src/Event/PreDestroyEvent.php
new file mode 100644
index 0000000000000000000000000000000000000000..1d75a7fe543155d96547d6cf9c2482cb65a252ce
--- /dev/null
+++ b/package_manager/src/Event/PreDestroyEvent.php
@@ -0,0 +1,9 @@
+<?php
+
+namespace Drupal\package_manager\Event;
+
+/**
+ * Event fired before the staging area is destroyed.
+ */
+class PreDestroyEvent extends StageEvent {
+}
diff --git a/package_manager/src/Event/PreRequireEvent.php b/package_manager/src/Event/PreRequireEvent.php
new file mode 100644
index 0000000000000000000000000000000000000000..93a122ad6db47fe397d592f0710b4759381f2cac
--- /dev/null
+++ b/package_manager/src/Event/PreRequireEvent.php
@@ -0,0 +1,9 @@
+<?php
+
+namespace Drupal\package_manager\Event;
+
+/**
+ * Event fired before packages are added to the staging area.
+ */
+class PreRequireEvent extends StageEvent {
+}
diff --git a/package_manager/src/Event/StageEvent.php b/package_manager/src/Event/StageEvent.php
new file mode 100644
index 0000000000000000000000000000000000000000..2aeadbf8103149db49187de2232ad8835a1317fc
--- /dev/null
+++ b/package_manager/src/Event/StageEvent.php
@@ -0,0 +1,11 @@
+<?php
+
+namespace Drupal\package_manager\Event;
+
+use Symfony\Contracts\EventDispatcher\Event;
+
+/**
+ * Base class for all events related to the life cycle of the staging area.
+ */
+abstract class StageEvent extends Event {
+}
diff --git a/package_manager/src/Stage.php b/package_manager/src/Stage.php
index d3a84009b5b16e023d88ccee9eee63ede43c9313..8f4e9e16d277d07ab9ee1452d86ffa643c760080 100644
--- a/package_manager/src/Stage.php
+++ b/package_manager/src/Stage.php
@@ -2,10 +2,19 @@
 
 namespace Drupal\package_manager;
 
+use Drupal\package_manager\Event\PostApplyEvent;
+use Drupal\package_manager\Event\PostCreateEvent;
+use Drupal\package_manager\Event\PostDestroyEvent;
+use Drupal\package_manager\Event\PostRequireEvent;
+use Drupal\package_manager\Event\PreApplyEvent;
+use Drupal\package_manager\Event\PreCreateEvent;
+use Drupal\package_manager\Event\PreDestroyEvent;
+use Drupal\package_manager\Event\PreRequireEvent;
 use PhpTuf\ComposerStager\Domain\BeginnerInterface;
 use PhpTuf\ComposerStager\Domain\CleanerInterface;
 use PhpTuf\ComposerStager\Domain\CommitterInterface;
 use PhpTuf\ComposerStager\Domain\StagerInterface;
+use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Creates and manages a staging area in which to install or update code.
@@ -52,6 +61,13 @@ class Stage {
    */
   protected $cleaner;
 
+  /**
+   * The event dispatcher service.
+   *
+   * @var \Symfony\Contracts\EventDispatcher\EventDispatcherInterface
+   */
+  protected $eventDispatcher;
+
   /**
    * Constructs a new Stage object.
    *
@@ -65,13 +81,16 @@ class Stage {
    *   The committer service from Composer Stager.
    * @param \PhpTuf\ComposerStager\Domain\CleanerInterface $cleaner
    *   The cleaner service from Composer Stager.
+   * @param \Symfony\Contracts\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher service.
    */
-  public function __construct(PathLocator $path_locator, BeginnerInterface $beginner, StagerInterface $stager, CommitterInterface $committer, CleanerInterface $cleaner) {
+  public function __construct(PathLocator $path_locator, BeginnerInterface $beginner, StagerInterface $stager, CommitterInterface $committer, CleanerInterface $cleaner, EventDispatcherInterface $event_dispatcher) {
     $this->pathLocator = $path_locator;
     $this->beginner = $beginner;
     $this->stager = $stager;
     $this->committer = $committer;
     $this->cleaner = $cleaner;
+    $this->eventDispatcher = $event_dispatcher;
   }
 
   /**
@@ -85,7 +104,10 @@ class Stage {
   public function create(?array $exclusions = []): void {
     $active_dir = $this->pathLocator->getActiveDirectory();
     $stage_dir = $this->pathLocator->getStageDirectory();
+
+    $this->eventDispatcher->dispatch(new PreCreateEvent());
     $this->beginner->begin($active_dir, $stage_dir, $exclusions);
+    $this->eventDispatcher->dispatch(new PostCreateEvent());
   }
 
   /**
@@ -97,7 +119,10 @@ class Stage {
   public function require(array $constraints): void {
     $command = array_merge(['require'], $constraints);
     $command[] = '--update-with-all-dependencies';
+
+    $this->eventDispatcher->dispatch(new PreRequireEvent());
     $this->stager->stage($command, $this->pathLocator->getStageDirectory());
+    $this->eventDispatcher->dispatch(new PostRequireEvent());
   }
 
   /**
@@ -111,17 +136,22 @@ class Stage {
   public function apply(?array $exclusions = []): void {
     $active_dir = $this->pathLocator->getActiveDirectory();
     $stage_dir = $this->pathLocator->getStageDirectory();
+
+    $this->eventDispatcher->dispatch(new PreApplyEvent());
     $this->committer->commit($stage_dir, $active_dir, $exclusions);
+    $this->eventDispatcher->dispatch(new PostApplyEvent());
   }
 
   /**
    * Deletes the staging area.
    */
   public function destroy(): void {
+    $this->eventDispatcher->dispatch(new PreDestroyEvent());
     $stage_dir = $this->pathLocator->getStageDirectory();
     if (is_dir($stage_dir)) {
       $this->cleaner->clean($stage_dir);
     }
+    $this->eventDispatcher->dispatch(new PostDestroyEvent());
   }
 
 }
diff --git a/package_manager/tests/src/Kernel/StageEventsTest.php b/package_manager/tests/src/Kernel/StageEventsTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..aba696089c610d3e4db645afabcfecbe417e8bf6
--- /dev/null
+++ b/package_manager/tests/src/Kernel/StageEventsTest.php
@@ -0,0 +1,89 @@
+<?php
+
+namespace Drupal\Tests\package_manager\Kernel;
+
+use Drupal\KernelTests\KernelTestBase;
+use Drupal\package_manager\Event\PostApplyEvent;
+use Drupal\package_manager\Event\PostCreateEvent;
+use Drupal\package_manager\Event\PostDestroyEvent;
+use Drupal\package_manager\Event\PostRequireEvent;
+use Drupal\package_manager\Event\PreApplyEvent;
+use Drupal\package_manager\Event\PreCreateEvent;
+use Drupal\package_manager\Event\PreDestroyEvent;
+use Drupal\package_manager\Event\PreRequireEvent;
+use Drupal\package_manager\Event\StageEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * Tests that the staging area fires events during its lifecycle.
+ *
+ * @group package_manager
+ */
+class StageEventsTest extends KernelTestBase implements EventSubscriberInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = [
+    'package_manager',
+    'package_manager_bypass',
+  ];
+
+  /**
+   * The events that were fired, in the order they were fired.
+   *
+   * @var string[]
+   */
+  private $events = [];
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getSubscribedEvents() {
+    return [
+      PreCreateEvent::class => 'handleEvent',
+      PostCreateEvent::class => 'handleEvent',
+      PreRequireEvent::class => 'handleEvent',
+      PostRequireEvent::class => 'handleEvent',
+      PreApplyEvent::class => 'handleEvent',
+      PostApplyEvent::class => 'handleEvent',
+      PreDestroyEvent::class => 'handleEvent',
+      PostDestroyEvent::class => 'handleEvent',
+    ];
+  }
+
+  /**
+   * Handles a staging area life cycle event.
+   *
+   * @param \Drupal\package_manager\Event\StageEvent $event
+   *   The event object.
+   */
+  public function handleEvent(StageEvent $event): void {
+    array_push($this->events, get_class($event));
+  }
+
+  /**
+   * Tests that the staging area fires life cycle events in a specific order.
+   */
+  public function testEvents(): void {
+    $this->container->get('event_dispatcher')->addSubscriber($this);
+
+    $stage = $this->container->get('package_manager.stage');
+    $stage->create();
+    $stage->require(['ext-json:*']);
+    $stage->apply();
+    $stage->destroy();
+
+    $this->assertSame($this->events, [
+      PreCreateEvent::class,
+      PostCreateEvent::class,
+      PreRequireEvent::class,
+      PostRequireEvent::class,
+      PreApplyEvent::class,
+      PostApplyEvent::class,
+      PreDestroyEvent::class,
+      PostDestroyEvent::class,
+    ]);
+  }
+
+}
diff --git a/tests/src/Functional/FileSystemOperationsTest.php b/tests/src/Functional/FileSystemOperationsTest.php
index fe42f99893c1303860d518bbfa0a4ead0173c50d..78a481fb0db55dee4748bad0b9f8eca3b7bafcf6 100644
--- a/tests/src/Functional/FileSystemOperationsTest.php
+++ b/tests/src/Functional/FileSystemOperationsTest.php
@@ -75,7 +75,8 @@ class FileSystemOperationsTest extends AutomaticUpdatesFunctionalTestBase {
       $this->container->get('package_manager.beginner'),
       $this->container->get('package_manager.stager'),
       $this->container->get('package_manager.committer'),
-      $cleaner
+      $cleaner,
+      $this->container->get('event_dispatcher')
     );
 
     $this->updater = new Updater(