diff --git a/.gitignore b/.gitignore
index 33f4a0ad64ae56bb17d14283e912901e2cf6bed9..9ae268bff042629ad7007a099de785d8cc2bd6b2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,6 +38,10 @@ jspm_packages
 # Optional npm cache directory
 .npm
 
+# Optional local Yarn settings
+.yarn
+.yarnrc
+
 # Optional REPL history
 .node_repl_history
 
diff --git a/.npmrc b/.npmrc
new file mode 100644
index 0000000000000000000000000000000000000000..c42da845b4490f8793a839b302915b4e54de71b4
--- /dev/null
+++ b/.npmrc
@@ -0,0 +1 @@
+engine-strict = true
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index dd7548679afea7457a301414b7079a6a3c8b37a6..b5e523ea45a368c90d0693f6d2e773ea45c6325e 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -23,6 +23,8 @@ inside the `MatrixEventProcessor` class.
 
 * You will need to [setup the bridge](https://github.com/Half-Shot/matrix-appservice-discord/tree/develop#setup-the-bridge) similarly to how we describe,
   but you should setup a homeserver locally on your development machine. We would recommend [Synapse](https://github.com/matrix-org/synapse).
+* The bridge uses `yarn` for dependency management and package scripts instead of `npm`.
+  For details, view the full setup instructions in the [README](README.md#set-up-the-bridge).
 
 ## Testing
 
@@ -33,5 +35,4 @@ Refer to the main matrix.org bridge contributing guide for instructions on how t
 [test](https://github.com/matrix-org/matrix-appservice-bridge/blob/develop/CONTRIBUTING.md#-tests--ci).
 
 Please bear in mind that you will need to cover the whole, or a reasonable
-degree of your code. You can check to see if you have with `npm run
-coverage`.
+degree of your code. You can check to see if you have with `yarn coverage`.
diff --git a/README.md b/README.md
index 13721918bcd467bbe6b9179a8535e25804d4ee9e..6fb297c77afad13ff2f62777035e8de7e73cab59 100644
--- a/README.md
+++ b/README.md
@@ -27,12 +27,17 @@ Please also be aware that this is an unoffical project worked on in our spare ti
 The bridge has been tested against the [Synapse](https://github.com/matrix-org/synapse) homeserver, although any homeserver
 that implements the [AS API](https://matrix.org/docs/spec/application_service/r0.1.0.html) should work with this bridge.
 
-The bridge supports any version of Node.js >= v12.X, including all [current releases](https://nodejs.org/en/about/releases/).
+The bridge supports any version of Node.js v12.X - v16.X. View the [releases](https://nodejs.org/en/about/releases/) for more details.
+
+The bridge uses Yarn for dependency management and package scripts.
+For the time being, **only Yarn Classic / v1 is supported.** To install it, follow [these instructions](https://classic.yarnpkg.com/en/docs/install).
+
+If you already have Yarn 2+ installed, you may configure just this project to use Yarn Classic
+by running ``yarn set version classic`` in the directory where you cloned this repository.
 
 ### Set up the bridge
 
-* Run ``npm install`` to grab the dependencies. `npm` may complain about peer dependencies, but you can safely ignore these.
-* Run ``npm run build`` to build the typescript into javascript.
+* Run ``yarn`` to grab the dependencies.
 * Copy ``config/config.sample.yaml`` to ``config.yaml`` and edit it to reflect your setup.
   * Note that you are expected to set ``domain`` and ``homeserverURL`` to your **public** host name.
   While localhost would work, it does not resolve correctly with Webhooks/Avatars.
@@ -95,7 +100,7 @@ should show up in the network list on Element and other clients.
 
 * Create a new application via https://discordapp.com/developers/applications
 * Make sure to create a bot user. Fill in ``config.yaml``
-* Run ``npm run addbot`` to get a authorisation link.
+* Run ``yarn addbot`` to get a authorisation link.
 * Give this link to owners of the guilds you plan to bridge.
 * Finally, you can join a room with ``#_discord_guildid_channelid``
   * These can be taken from the url ("/$GUILDID/$CHANNELID") when you are in a channel.
@@ -108,7 +113,7 @@ should show up in the network list on Element and other clients.
 ### Running the Bridge
 
 * For the bot to appear online on Discord you need to run the bridge itself.
-* ``npm start``
+* ``yarn start``
 * Particular configuration keys can be overridden by defining corresponding environment variables. For instance, `auth.botToken` can be set with `APPSERVICE_DISCORD_AUTH_BOT_TOKEN`.
 
 [Howto](./docs/howto.md)
diff --git a/changelog.d/796.misc b/changelog.d/796.misc
new file mode 100644
index 0000000000000000000000000000000000000000..2fd2578607ab6ba0df83a3a7be70d622dd68bd02
--- /dev/null
+++ b/changelog.d/796.misc
@@ -0,0 +1 @@
+Use `yarn` instead of `npm` for package management and scripts.
diff --git a/docs/howto.md b/docs/howto.md
index 3657a390e0f7641770321950ab684d40cab68bfb..d1c96fde737cc5f14386c29fc1fca3ecab409f1f 100644
--- a/docs/howto.md
+++ b/docs/howto.md
@@ -15,8 +15,8 @@ is formatted as https://discord.com/channels/``guildid``/``channelid``
 
 * The ``adminme`` script is provided to set Admin/Moderator or any other custom power level to a specific user.
 * e.g. To set Alice to Admin on her ``example.com`` HS on default config. (``config.yaml``)
-  * ``npm run adminme -- -r '!AbcdefghijklmnopqR:example.com' -u '@Alice:example.com' -p '100'``
-  * Run ``npm run adminme -- -h`` for usage.
+  * ``yarn adminme -r '!AbcdefghijklmnopqR:example.com' -u '@Alice:example.com' -p '100'``
+  * Run ``yarn adminme -h`` for usage.
 
 Please note that `!AbcdefghijklmnopqR:example.com` is the internal room id and will always begin with `!`.
 You can find this internal id in the room settings in Element.
diff --git a/docs/puppeting.md b/docs/puppeting.md
index 0d75f621b391202668cb3b04219e56ae6d0fcf76..f233756943bdf1628fba9cc8f320084773022fe9 100644
--- a/docs/puppeting.md
+++ b/docs/puppeting.md
@@ -39,5 +39,5 @@ You should be able to puppet with 2FA enabled on your account
 
 * Follow https://discordhelp.net/discord-token to find your discord token.
 * Stop the bridge, if it is running.
-* Run `npm run usertool -- --add` and follow the instructions.
+* Run `yarn usertool --add` and follow the instructions.
 * If all is well, you can start the bridge.
diff --git a/package.json b/package.json
index 1a284e9852ad4945e29159017c900abfdab2125b..25dea0c07e06111771633aaf1814986c635d288a 100644
--- a/package.json
+++ b/package.json
@@ -3,14 +3,18 @@
   "version": "1.0.0",
   "description": "A bridge between Matrix and Discord",
   "main": "discordas.js",
+  "engines": {
+    "npm": "please-use-yarn",
+    "node": "12.x - 16.x"
+  },
   "scripts": {
     "test": "mocha -r ts-node/register test/config.ts test/test_*.ts test/**/test_*.ts",
     "lint": "eslint -c .eslintrc --max-warnings 200 src/**/*.ts test/**/*.ts",
     "coverage": "tsc && nyc mocha build/test/config.js build/test",
     "build": "tsc",
-    "postinstall": "npm run build",
-    "start": "npm run-script build && node ./build/src/discordas.js -c config.yaml",
-    "debug": "npm run-script build && node --inspect ./build/src/discordas.js -c config.yaml",
+    "postinstall": "yarn build",
+    "start": "yarn build && node ./build/src/discordas.js -c config.yaml",
+    "debug": "yarn build && node --inspect ./build/src/discordas.js -c config.yaml",
     "addbot": "node ./build/tools/addbot.js",
     "adminme": "node ./build/tools/adminme.js",
     "usertool": "node ./build/tools/userClientTools.js",