Repository: django/django
Issue category: Feature Request

Issue:
Add warning to runserver that it should not be used for production
Description
	 
As per this discussion on the ​forum, I think adding a warning to the start of runserver would be valuable to those new to Django and a healthy reminder to those coming back to Django. 
The wording of the warning is:
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
For more information on production servers see the documentation: https://docs.djangoproject.com/en/5.0/howto/deployment/
Additionally a flag should be added to optionally hide the warning. --hide-unsuitable-for-production was a suggestion.
Finally the following 2 pages of the documentation should have add some wording to highlight that a deployed project should not use runserver.
​https://docs.djangoproject.com/en/5.0/howto/deployment/ (Add a warning or paragraph that mentions switching)
​https://docs.djangoproject.com/en/5.0/howto/deployment/checklist/ (Add a section to switch away from runserver)
Add warning to runserver that it should not be used for production
Description
	 
As per this discussion on the ​forum, I think adding a warning to the start of runserver would be valuable to those new to Django and a healthy reminder to those coming back to Django. 
The wording of the warning is:
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
For more information on production servers see the documentation: https://docs.djangoproject.com/en/5.0/howto/deployment/
Additionally a flag should be added to optionally hide the warning. --hide-unsuitable-for-production was a suggestion.
Finally the following 2 pages of the documentation should have add some wording to highlight that a deployed project should not use runserver.
​https://docs.djangoproject.com/en/5.0/howto/deployment/ (Add a warning or paragraph that mentions switching)
​https://docs.djangoproject.com/en/5.0/howto/deployment/checklist/ (Add a section to switch away from runserver)


Hints:
['I think it\'s worth highlighting that it does say "development server": Starting development server at http://127.0.0.1:8000/ Quit the server with CTRL-BREAK. We also have a warning in the \u200brunserver docs and a \u200bwarning in the tutorial (note that the tutorial runserver output would need to be updated if we make a change here). So I think this is not that we don\'t have this already but a request to make this information more prominent', 1720668622.0]
['This will be the new output by default. Warning can be disabled by using --hide-unsuitable-for-production flag Starting development server at http://127.0.0.1:8000/ Quit the server with CTRL-BREAK. WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. For more information on production servers see the documentation: https://docs.djangoproject.com/en/5.0/howto/deployment/', 1720675079.0]
['Task list: add flag to runserver command add new message with flag to hide it update output at \u200bhttps://docs.djangoproject.com/en/5.0/intro/tutorial01/#the-development-server update reference docs: \u200bhttps://docs.djangoproject.com/en/5.0/ref/django-admin/#runserver update deployment checklist update deployment docs with a warning add tests for new flag update existing tests to include extended output', 1722421918.0]
['\u200bPR', 1722425099.0]
['Updated the PR.', 1723026415.0]
['I think it\'s worth highlighting that it does say "development server": Starting development server at http://127.0.0.1:8000/ Quit the server with CTRL-BREAK. We also have a warning in the \u200brunserver docs and a \u200bwarning in the tutorial (note that the tutorial runserver output would need to be updated if we make a change here). So I think this is not that we don\'t have this already but a request to make this information more prominent', 1720668622.0]
['This will be the new output by default. Warning can be disabled by using --hide-unsuitable-for-production flag Starting development server at http://127.0.0.1:8000/ Quit the server with CTRL-BREAK. WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. For more information on production servers see the documentation: https://docs.djangoproject.com/en/5.0/howto/deployment/', 1720675079.0]
['Task list: add flag to runserver command add new message with flag to hide it update output at \u200bhttps://docs.djangoproject.com/en/5.0/intro/tutorial01/#the-development-server update reference docs: \u200bhttps://docs.djangoproject.com/en/5.0/ref/django-admin/#runserver update deployment checklist update deployment docs with a warning add tests for new flag update existing tests to include extended output', 1722421918.0]
['\u200bPR', 1722425099.0]
['Updated the PR.', 1723026415.0]

Patch:
diff --git a/django/core/management/commands/runserver.py b/django/core/management/commands/runserver.py
index 132ee4c0795a..3795809a1226 100644
--- a/django/core/management/commands/runserver.py
+++ b/django/core/management/commands/runserver.py
@@ -188,3 +188,12 @@ def on_bind(self, server_port):
             f"Quit the server with {quit_command}.",
             file=self.stdout,
         )
+        if os.environ.get("HIDE_PRODUCTION_WARNING") != "true":
+            self.stdout.write(
+                self.style.WARNING(
+                    "WARNING: This is a development server. Do not use it in a "
+                    "production setting. Use a production WSGI or ASGI server "
+                    "instead.\nFor more information on production servers see: "
+                    "https://docs.djangoproject.com/en/stable/howto/deployment/"
+                )
+            )
diff --git a/docs/intro/tutorial01.txt b/docs/intro/tutorial01.txt
index db59ca49df75..0536eca2f776 100644
--- a/docs/intro/tutorial01.txt
+++ b/docs/intro/tutorial01.txt
@@ -134,6 +134,9 @@ You'll see the following output on the command line:
     Starting development server at http://127.0.0.1:8000/
     Quit the server with CONTROL-C.
 
+    WARNING: This is a development server. Do not use it in a production setting. Use a production WSGI or ASGI server instead.
+    For more information on production servers see: https://docs.djangoproject.com/en/stable/howto/deployment/
+
 .. note::
     Ignore the warning about unapplied database migrations for now; we'll deal
     with the database shortly.
diff --git a/docs/ref/django-admin.txt b/docs/ref/django-admin.txt
index 8173224e4ceb..52eaaa331b65 100644
--- a/docs/ref/django-admin.txt
+++ b/docs/ref/django-admin.txt
@@ -947,6 +947,20 @@ multithreaded by default.
 Uses IPv6 for the development server. This changes the default IP address from
 ``127.0.0.1`` to ``::1``.
 
+.. envvar:: HIDE_PRODUCTION_WARNING
+
+.. versionadded:: 5.2
+
+By default, a warning is printed to the console that ``runserver`` is not
+suitable for production:
+
+.. code-block:: text
+
+    WARNING: This is a development server. Do not use it in a production setting. Use a production WSGI or ASGI server instead.
+    For more information on production servers see: https://docs.djangoproject.com/en/stable/howto/deployment/
+
+Set this environment variable to ``"true"`` to hide this warning.
+
 Examples of using different ports and addresses
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/docs/releases/5.2.txt b/docs/releases/5.2.txt
index 92bb501d61cb..6b63bc9524fd 100644
--- a/docs/releases/5.2.txt
+++ b/docs/releases/5.2.txt
@@ -194,7 +194,10 @@ Logging
 Management Commands
 ~~~~~~~~~~~~~~~~~~~
 
-* ...
+* A new warning is printed to the console when running :djadmin:`runserver` that
+  ``runserver`` is unsuitable for production. This warning can be hidden by
+  setting the :envvar:`HIDE_PRODUCTION_WARNING` environment variable to
+  ``"true"``.
 
 Migrations
 ~~~~~~~~~~


Test patch:
diff --git a/tests/admin_scripts/tests.py b/tests/admin_scripts/tests.py
index 2e77f2c97a62..67362460a99d 100644
--- a/tests/admin_scripts/tests.py
+++ b/tests/admin_scripts/tests.py
@@ -1597,6 +1597,13 @@ def test_zero_ip_addr(self):
             "Starting development server at http://0.0.0.0:8000/",
             self.output.getvalue(),
         )
+        self.assertIn(
+            "WARNING: This is a development server. Do not use it in a "
+            "production setting. Use a production WSGI or ASGI server instead."
+            "\nFor more information on production servers see: "
+            "https://docs.djangoproject.com/en/stable/howto/deployment/",
+            self.output.getvalue(),
+        )
 
     def test_on_bind(self):
         self.cmd.addr = "127.0.0.1"
@@ -1606,6 +1613,30 @@ def test_on_bind(self):
             "Starting development server at http://127.0.0.1:14437/",
             self.output.getvalue(),
         )
+        self.assertIn(
+            "WARNING: This is a development server. Do not use it in a "
+            "production setting. Use a production WSGI or ASGI server instead."
+            "\nFor more information on production servers see: "
+            "https://docs.djangoproject.com/en/stable/howto/deployment/",
+            self.output.getvalue(),
+        )
+
+    @mock.patch.dict(os.environ, {"HIDE_PRODUCTION_WARNING": "true"})
+    def test_hide_production_warning_with_environment_variable(self):
+        self.cmd.addr = "0"
+        self.cmd._raw_ipv6 = False
+        self.cmd.on_bind("8000")
+        self.assertIn(
+            "Starting development server at http://0.0.0.0:8000/",
+            self.output.getvalue(),
+        )
+        self.assertNotIn(
+            "WARNING: This is a development server. Do not use it in a "
+            "production setting. Use a production WSGI or ASGI server instead."
+            "\nFor more information on production servers see: "
+            "https://docs.djangoproject.com/en/stable/howto/deployment/",
+            self.output.getvalue(),
+        )
 
     @unittest.skipUnless(socket.has_ipv6, "platform doesn't support IPv6")
     def test_runner_addrport_ipv6(self):