diff --git a/lms/djangoapps/courseware/tests/test_views.py b/lms/djangoapps/courseware/tests/test_views.py
index 319075aa3f379bbbf84012ac2e77aae25813a19c..9043aa411d8c19350a5843e676a7188a1140293c 100644
--- a/lms/djangoapps/courseware/tests/test_views.py
+++ b/lms/djangoapps/courseware/tests/test_views.py
@@ -60,6 +60,9 @@ from lms.djangoapps.certificates.models import (
 from lms.djangoapps.certificates.tests.factories import CertificateInvalidationFactory, GeneratedCertificateFactory
 from lms.djangoapps.commerce.models import CommerceConfiguration
 from lms.djangoapps.commerce.utils import EcommerceService
+from lms.djangoapps.courseware.views.index import show_courseware_mfe_link
+from lms.djangoapps.courseware.toggles import REDIRECT_TO_COURSEWARE_MICROFRONTEND
+from lms.djangoapps.courseware.url_helpers import get_microfrontend_url
 from lms.djangoapps.grades.config.waffle import ASSUME_ZERO_GRADE_IF_ABSENT
 from lms.djangoapps.grades.config.waffle import waffle as grades_waffle
 from lms.djangoapps.verify_student.models import VerificationDeadline
@@ -3213,3 +3216,59 @@ class DatesTabTestCase(ModuleStoreTestCase):
                 self.assertNotContains(response, '<div class="pill due">')
                 # Should have verified pills for audit enrollments
                 self.assertContains(response, '<div class="pill verified">')
+
+
+class TestShowCoursewareMFE(TestCase):
+    """
+    Make sure we're showing the Courseware MFE link when appropriate.
+    """
+    def test_when_to_show(self):
+        course_key = CourseKey.from_string("course-v1:OpenEdX+MFE+2020")
+        global_staff_user = UserFactory(username="global_staff", is_staff=True)
+        user = UserFactory(username="normal", is_staff=False)
+
+        # We never show when the feature is entirely disabled.
+        with patch.dict(settings.FEATURES, {'ENABLE_COURSEWARE_MICROFRONTEND': False}):
+            self.assertFalse(show_courseware_mfe_link(global_staff_user, True, course_key))
+            self.assertFalse(show_courseware_mfe_link(user, True, course_key))
+            self.assertFalse(show_courseware_mfe_link(user, False, course_key))
+
+        # If it's enabled at the platform level, what we do depends on the
+        # CourseWaffleFlag and type of user...
+        with patch.dict(settings.FEATURES, {'ENABLE_COURSEWARE_MICROFRONTEND': True}):
+            # If the feature is enabled at the platform level, we always display
+            # the MFE link to global staff. But course staff only see it if the
+            # CourseWaffleFlag is also enabled for that course. Regular users
+            # never see the link.
+            with override_waffle_flag(REDIRECT_TO_COURSEWARE_MICROFRONTEND, False):
+                self.assertTrue(show_courseware_mfe_link(global_staff_user, True, course_key))
+                self.assertFalse(show_courseware_mfe_link(user, True, course_key))
+                self.assertFalse(show_courseware_mfe_link(user, False, course_key))
+
+            # If both the feature flag and CourseWaffleFlag are enabled, we should show
+            # to global and course staff, but not normal users.
+            with override_waffle_flag(REDIRECT_TO_COURSEWARE_MICROFRONTEND, True):
+                self.assertTrue(show_courseware_mfe_link(global_staff_user, True, course_key))
+                self.assertTrue(show_courseware_mfe_link(user, True, course_key))
+                self.assertFalse(show_courseware_mfe_link(user, False, course_key))
+
+    @override_settings(LEARNING_MICROFRONTEND_URL='https://learningmfe.openedx.org')
+    def test_url_generation(self):
+        course_key = CourseKey.from_string("course-v1:OpenEdX+MFE+2020")
+        section_key = UsageKey.from_string("block-v1:OpenEdX+MFE+2020+type@sequential+block@Introduction")
+        unit_id = "block-v1:OpenEdX+MFE+2020+type@vertical+block@Getting_To_Know_You"
+        assert get_microfrontend_url(course_key) == (
+            'https://learningmfe.openedx.org'
+            '/course/course-v1:OpenEdX+MFE+2020'
+        )
+        assert get_microfrontend_url(course_key, section_key, '') == (
+            'https://learningmfe.openedx.org'
+            '/course/course-v1:OpenEdX+MFE+2020'
+            '/block-v1:OpenEdX+MFE+2020+type@sequential+block@Introduction'
+        )
+        assert get_microfrontend_url(course_key, section_key, unit_id) == (
+            'https://learningmfe.openedx.org'
+            '/course/course-v1:OpenEdX+MFE+2020'
+            '/block-v1:OpenEdX+MFE+2020+type@sequential+block@Introduction'
+            '/block-v1:OpenEdX+MFE+2020+type@vertical+block@Getting_To_Know_You'
+        )
diff --git a/lms/djangoapps/courseware/toggles.py b/lms/djangoapps/courseware/toggles.py
index 0058f7631f3b9681be31f47d30441c769cdc1ded..97ed26d0dea6981428cd6b89d75d3ec5c8e7f255 100644
--- a/lms/djangoapps/courseware/toggles.py
+++ b/lms/djangoapps/courseware/toggles.py
@@ -2,7 +2,7 @@
 Toggles for courseware in-course experience.
 """
 
-from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
+from django.conf import settings
 from openedx.core.djangoapps.waffle_utils import CourseWaffleFlag, WaffleFlagNamespace
 
 # Namespace for courseware waffle flags.
@@ -25,6 +25,6 @@ REDIRECT_TO_COURSEWARE_MICROFRONTEND = CourseWaffleFlag(WAFFLE_FLAG_NAMESPACE, '
 
 def should_redirect_to_courseware_microfrontend(course_key):
     return (
-        configuration_helpers.get_value('ENABLE_COURSEWARE_MICROFRONTEND') and
+        settings.FEATURES.get('ENABLE_COURSEWARE_MICROFRONTEND') and
         REDIRECT_TO_COURSEWARE_MICROFRONTEND.is_enabled(course_key)
     )
diff --git a/lms/djangoapps/courseware/url_helpers.py b/lms/djangoapps/courseware/url_helpers.py
index 52bea116a8d83867e69e71ce23bc1ac57084a9f3..eb0e06fd79f5b1f4cc5e45b0decfa95f1c83406d 100644
--- a/lms/djangoapps/courseware/url_helpers.py
+++ b/lms/djangoapps/courseware/url_helpers.py
@@ -55,44 +55,36 @@ def get_redirect_url(course_key, usage_key, request=None):
     return redirect_url
 
 
-def get_microfrontend_redirect_url(course_key, path=None):
+def get_microfrontend_url(course_key, sequence_key=None, unit_key=None):
     """
-    The micro-frontend determines the user's position in the vertical via
-    a separate API call, so all we need here is the course_key, section, and vertical
-    IDs to format it's URL.
+    Return a str with the URL for the specified content in the Courseware MFE.
 
-    It is also capable of determining our section and vertical if they're not present.  Fully
-    specifying it all is preferable, though, as the micro-frontend can save itself some work,
-    resulting in a better user experience.
+    The micro-frontend determines the user's position in the vertical via
+    a separate API call, so all we need here is the course_key, section, and
+    vertical IDs to format it's URL. For simplicity and performance reasons,
+    this method does not inspect the modulestore to try to figure out what
+    Unit/Vertical a sequence is in. If you try to pass in a unit_key without
+    a sequence_key, the value will just be ignored and you'll get a URL pointing
+    to just the course_key.
+
+    It is also capable of determining our section and vertical if they're not
+    present.  Fully specifying it all is preferable, though, as the
+    micro-frontend can save itself some work, resulting in a better user
+    experience.
 
     We're building a URL like this:
 
     http://localhost:2000/course-v1:edX+DemoX+Demo_Course/block-v1:edX+DemoX+Demo_Course+type@sequential+block@19a30717eff543078a5d94ae9d6c18a5/block-v1:edX+DemoX+Demo_Course+type@vertical+block@4a1bba2a403f40bca5ec245e945b0d76
+
+    `course_key`, `sequence_key`, and `unit_key` can be either OpaqueKeys or
+    strings. They're only ever used to concatenate a URL string.
     """
+    mfe_link = '{}/course/{}'.format(settings.LEARNING_MICROFRONTEND_URL, course_key)
 
-    redirect_url = '{base_url}/{prefix}/{course_key}'.format(
-        base_url=settings.LEARNING_MICROFRONTEND_URL,
-        prefix='course',
-        course_key=course_key
-    )
-
-    if path is None:
-        return redirect_url
-
-    # The first four elements of the path list are the ones we care about here:
-    # - course
-    # - chapter
-    # - sequence
-    # - vertical
-    # We skip course because we already have it from our argument above, and we skip chapter
-    # because the micro-frontend URL doesn't include it.
-    if len(path) > 2:
-        redirect_url += '/{sequence_key}'.format(
-            sequence_key=path[2]
-        )
-    if len(path) > 3:
-        redirect_url += '/{vertical_key}'.format(
-            vertical_key=path[3]
-        )
+    if sequence_key:
+        mfe_link += '/{}'.format(sequence_key)
 
-    return redirect_url
+        if unit_key:
+            mfe_link += '/{}'.format(unit_key)
+
+    return mfe_link
diff --git a/lms/djangoapps/courseware/views/index.py b/lms/djangoapps/courseware/views/index.py
index 4a0fcdd7195e69562e20fccf692c1a9cf051f983..7dc0eeb5ecd2a80dfec4f923d31e781e59d5f72b 100644
--- a/lms/djangoapps/courseware/views/index.py
+++ b/lms/djangoapps/courseware/views/index.py
@@ -31,6 +31,8 @@ from web_fragments.fragment import Fragment
 from edxmako.shortcuts import render_to_response, render_to_string
 from lms.djangoapps.courseware.courses import allow_public_access
 from lms.djangoapps.courseware.exceptions import CourseAccessRedirect
+from lms.djangoapps.courseware.toggles import should_redirect_to_courseware_microfrontend
+from lms.djangoapps.courseware.url_helpers import get_microfrontend_url
 from lms.djangoapps.experiments.utils import get_experiment_user_metadata_context
 from lms.djangoapps.gating.api import get_entrance_exam_score_ratio, get_entrance_exam_usage_key
 from lms.djangoapps.grades.api import CourseGradeFactory
@@ -414,6 +416,7 @@ class CoursewareIndex(View):
             settings.FEATURES.get('ENABLE_COURSEWARE_SEARCH') or
             (settings.FEATURES.get('ENABLE_COURSEWARE_SEARCH_FOR_COURSE_STAFF') and self.is_staff)
         )
+        staff_access = self.is_staff
 
         courseware_context = {
             'csrf': csrf(self.request)['csrf_token'],
@@ -423,7 +426,7 @@ class CoursewareIndex(View):
             'section': self.section,
             'init': '',
             'fragment': Fragment(),
-            'staff_access': self.is_staff,
+            'staff_access': staff_access,
             'can_masquerade': self.can_masquerade,
             'masquerade': self.masquerade,
             'supports_preview_menu': True,
@@ -482,12 +485,24 @@ class CoursewareIndex(View):
                 table_of_contents['previous_of_active_section'],
                 table_of_contents['next_of_active_section'],
             )
-            courseware_context['unit'] = section_context.get('activate_block_id', '')
+            unit_id = section_context.get('activate_block_id', '')
+            courseware_context['unit'] = unit_id
             courseware_context['fragment'] = self.section.render(self.view, section_context)
 
             if self.section.position and self.section.has_children:
                 self._add_sequence_title_to_context(courseware_context)
 
+        # Courseware MFE link
+        if show_courseware_mfe_link(request.user, staff_access, self.course.id):
+            if self.section:
+                courseware_context['microfrontend_link'] = get_microfrontend_url(
+                    self.course.id, self.section.location, unit_id
+                )
+            else:
+                courseware_context['microfrontend_link'] = get_microfrontend_url(self.course.id)
+        else:
+            courseware_context['microfrontend_link'] = None
+
         return courseware_context
 
     def _add_sequence_title_to_context(self, courseware_context):
@@ -606,3 +621,26 @@ def save_positions_recursively_up(user, request, field_data_cache, xmodule, cour
             save_child_position(parent, current_module.location.block_id)
 
         current_module = parent
+
+
+def show_courseware_mfe_link(user, staff_access, course_key):
+    """
+    Return whether to display the button to switch to the Courseware MFE.
+    """
+    # The MFE isn't enabled at all, so don't show the button.
+    if not settings.FEATURES.get('ENABLE_COURSEWARE_MICROFRONTEND'):
+        return False
+
+    # Global staff members always get to see the courseware MFE button if
+    # the basic feature is enabled at all, regardless of whether a course
+    # has enabled it via flag.
+    if user.is_staff:
+        return True
+
+    # If you have course staff access, you see this link only if your
+    # students would be redirected to the new experience (course staff are
+    # never automatically redirected).
+    if staff_access and should_redirect_to_courseware_microfrontend(course_key):
+        return True
+
+    return False
diff --git a/lms/envs/common.py b/lms/envs/common.py
index 399b59f549b214eb4df5c2d293289aff933d3142..071672918fe3482e3575687c6ec3c7819ec6673a 100644
--- a/lms/envs/common.py
+++ b/lms/envs/common.py
@@ -416,6 +416,19 @@ FEATURES = {
     # .. toggle_status: supported
     # .. toggle_warnings: None
     'ENABLE_CHANGE_USER_PASSWORD_ADMIN': False,
+
+    # .. toggle_name: ENABLE_COURSEWARE_MICROFRONTEND
+    # .. toggle_implementation: DjangoSetting
+    # .. toggle_default: False
+    # .. toggle_description: Set to True to enable the Courseware MFE at the platform level for global staff (see REDIRECT_TO_COURSEWARE_MICROFRONTEND for course rollout)
+    # .. toggle_category: admin
+    # .. toggle_use_cases: open_edx
+    # .. toggle_creation_date: 2020-03-05
+    # .. toggle_expiration_date: None
+    # .. toggle_tickets: 'https://github.com/edx/edx-platform/pull/23317'
+    # .. toggle_status: supported
+    # .. toggle_warnings: Also set settings.LEARNING_MICROFRONTEND_URL and see REDIRECT_TO_COURSEWARE_MICROFRONTEND for rollout.
+    'ENABLE_COURSEWARE_MICROFRONTEND': False,
 }
 
 # Settings for the course reviews tool template and identification key, set either to None to disable course reviews
diff --git a/lms/envs/devstack.py b/lms/envs/devstack.py
index b440eb38410bf99c58caa4c0e70184b7b148f136..9e01cc1357815f3485ed445684e91302b23f8cc5 100644
--- a/lms/envs/devstack.py
+++ b/lms/envs/devstack.py
@@ -219,6 +219,9 @@ FEATURES['ENABLE_COSMETIC_DISPLAY_PRICE'] = True
 ######################### Program Enrollments #####################
 FEATURES['ENABLE_ENROLLMENT_RESET'] = True
 
+######################### New Courseware MFE #####################
+FEATURES['ENABLE_COURSEWARE_MICROFRONTEND'] = True
+
 ########################## Third Party Auth #######################
 
 if FEATURES.get('ENABLE_THIRD_PARTY_AUTH') and 'third_party_auth.dummy.DummyBackend' not in AUTHENTICATION_BACKENDS:
diff --git a/lms/templates/preview_menu.html b/lms/templates/preview_menu.html
index a863b2d41b74afa5844e1f84163acbdacd957262..cd7da9f5031027ef3afd07cd4345cec33f988e5d 100644
--- a/lms/templates/preview_menu.html
+++ b/lms/templates/preview_menu.html
@@ -19,16 +19,6 @@ show_preview_menu = course and can_masquerade and supports_preview_menu
     def selected(is_selected):
       return "selected" if is_selected else ""
 
-    def get_mfe_link():
-      if section:
-          mfe_link = '{}/course/{}/{}'.format(settings.LEARNING_MICROFRONTEND_URL, course.id, section.location)
-          if unit:
-            mfe_link += '/' + unit
-      else:
-        mfe_link = None
-      return mfe_link
-
-    mfe_link = get_mfe_link()
     course_partitions = get_all_partitions_for_course(course)
     masquerade_user_name = masquerade.user_name if masquerade else None
     masquerade_group_id = masquerade.group_id if masquerade else None
@@ -76,9 +66,9 @@ show_preview_menu = course and can_masquerade and supports_preview_menu
                     </p>
                 </div>
             % endif
-            % if user.is_staff and mfe_link:
+            % if microfrontend_link:
             <div style="flex-grow: 1; text-align: right;">
-                <a class="btn btn-primary" style="border: solid 1px white;" href="${mfe_link}">
+                <a class="btn btn-primary" style="border: solid 1px white;" href="${microfrontend_link}">
                     ${_("View this unit in the new experience")}
                 </a>
             </div>