diff --git a/docs/tutorials/beginner/graphql.mdx b/docs/tutorials/beginner/graphql.mdx
new file mode 100644
index 0000000..294c15b
--- /dev/null
+++ b/docs/tutorials/beginner/graphql.mdx
@@ -0,0 +1,118 @@
+import LearningObjectives from "@site/src/components/LearningObjectives";
+
+# GraphQL Fundamentals
+GraphQL is a powerful and flexible way to fetch data from the D&D 5e SRD API. In this tutorial, we will learn how to build and try out a range of GraphQL queries using the [Apollo Sandbox Explorer](https://studio.apollographql.com/sandbox?endpoint=https%3A%2F%2Fwww.dnd5eapi.co%2Fgraphql).
+
+
+
+## From REST to GraphQL
+In the [Getting Started](./getting-started.md) tutorial, we used `curl` to make an HTTP `GET` request to a specific URL that returned the data we wanted. Using that approach, the URL we made a request to corresponded directly to the resource we wanted to fetch; `/api/ability-scores/cha` refers to the resource within the `ability-scores` collection which has the index `cha`.
+
+This is one of the defining features of a RESTful API: a URL corresponds to a resource. The RESTful endpoints of the D&D 5e SRD API follow this uniform interface to make it easy for us to fetch the resources we need, but they don't allow us much control over what data is returned by the API.
+
+For example, if we make a `GET` request to `https://www.dnd5eapi.co/api/monsters`, we will receive only the `index`, `name` and `url` of all the monsters in the SRD database. This is a sensible default, as it gives us the information we need to discover all the monsters, while keeping the response relatively lightweight by excluding unnecessary details. But what if I want to know more about a specific monster?
+
+Making a request to one of the `url`s provided, such as `/api/monsters/aboleth`, we will receive *all* of the data about the Aboleth, including its stats, actions, proficiencies, etc. But what if we just wanted to know the Aboleth's armor class? We've just wasted time and bandwidth transporting all that extra information.
+
+And what if we want to fetch the armor classes of *all* of the monsters? Using the REST API, we would have to make a separate request for every single monster in the API - that's 334 HTTP requests! Not only would this be slow, it would be a pain to implement.
+
+This is where GraphQL saves the day. GraphQL stands for "Graph Query Language". It is a computer language that allows us to query an API much more flexibly than is allowed by the REST API. GraphQL allows us to specify exactly which parts of a resource we want to receive, and to request that data for many resources all in one request. In this tutorial, we will look at how we can build and execute powerful queries against the D&D 5e SRD API using GraphQL.
+
+## Sandbox Explorer
+As well as data, GraphQL servers are able to serve their own schemas and documentation. This allows us to use tools such as the [Apollo Sandbox Explorer](https://studio.apollographql.com/sandbox?endpoint=https%3A%2F%2Fwww.dnd5eapi.co%2Fgraphql) to discover the API's capabilities and to build and test our queries.
+
+Open the explorer in a new tab now so that you can follow along with the tutorial. You should see a page like this:
+
+![A screenshot of the Apollo Sandbox Explorer](/img/tutorial/graphql/01-explorer.png)
+
+On the left we can see the documentation - a list of all the resources we can query. In the middle are the text boxes where we can write our GraphQL query, as well as any variables that we might want to pass with the request. Finally on the right is the "Response" panel, where any results of queries we execute will be displayed.
+
+## Our First Query
+Let's start by getting a list of all the monsters in the database. To do this, we can build a query using the panel on the left-hand side of the explorer. Scroll down to "monsters" and click the ("plus") icon to the left. You should then be presented with a list of attributes that we can request. You should also see the following code appear in the editor:
+
+```graphql
+query Monsters {
+ monsters {
+
+ }
+}
+```
+
+From the list on the left-hand side, scroll down to the "Fields" section and select `name` and `index`, and then click the blue "Monsters" button in the top-right corner of the "Operation" box to execute the query. The result should look like this:
+
+![A screenshot of the Sandbox Explorer with the query and its results](/img/tutorial/graphql/02-query-results.png)
+
+In the results pane, we can see the list of all the monsters in the database, and each entry only has the attributes we requested.
+
+## Nested Attributes
+Now let's try getting the armor class of each monster. If we select the `armor_class` attribute from the list of fields, it appears in our query with a set of curly braces, like so:
+
+```graphql
+query Monsters {
+ monsters {
+ name
+ index
+ armor_class {
+
+ }
+ }
+}
+```
+
+We are also presented with a list of fields that exist inside the `armor_class` object. Let's select `value` and `type`, and execute the query again. Here's what we should see now:
+
+![A screenshot of the Sandbox Explorer with the nested query and its results](/img/tutorial/graphql/03-nested-query-results.png)
+
+Here we can see that each monster now has an array of possible armor classes, and we can see the value and type of each one, but we haven't fetched any unwanted data, like the conditions or descriptions of the armor classes.
+
+Take a moment now to try building some queries of your own. Use the documentation on the left of the screen to build your queries, or for an extra challenge, try writing a query by hand.
+
+## Fetching a Single Resource
+You may have noticed that each top-level field in the documentation comes in a singular and a plural form. For example, `abilityScore` and `abilityScores`, `monster` and `monsters`. The plural forms denote fields that allow us to query a collection of resources, as we have seen with the `monsters` field, but the singular forms (e.g. `monster`) allow us to query a single resource. All we need is the resource's `index`, which is its unique identifier.
+
+Let's try this out now.
+
+Enter the following query into the Explorer:
+
+```graphql
+query Monster {
+ monster(index: "aboleth") {
+ name
+ challenge_rating
+ hit_points
+ }
+}
+```
+
+You will notice that we are making use of the `index` argument to specify that we want information about the Aboleth. When we execute the query, this is exactly what we get.
+
+But what if we don't always want to fetch information about the same monster? To facilitate this, we can use variables. The query below declares a variable called `$index`, which must be passed a `String` value when we make our request.
+
+```graphql
+query Monster($index: String) {
+ monster(index: $index) {
+ name
+ challenge_rating
+ hit_points
+ }
+}
+```
+
+To pass variables, we can provide a JSON object along with our request, where each field corresponds to a variable. Add the following JSON code to the "Variables" box in the explorer:
+
+```json
+{
+ "index": "aboleth"
+}
+```
+
+Execute the query and we should see the same results as before, except this time we can request a different monster just by changing the value of our `index` variable. Take this opportunity to pass in different indices and observe how this affects the response.
+
+## Next Steps
+Now that we can build and test a range of GraphQL queries, we are ready to apply these skills to a real project. In future tutorials, we will bring together GraphQL and other languages and technologies to build fun and interesting tools.
\ No newline at end of file
diff --git a/static/img/tutorial/graphql/01-explorer.png b/static/img/tutorial/graphql/01-explorer.png
new file mode 100644
index 0000000..252df0a
Binary files /dev/null and b/static/img/tutorial/graphql/01-explorer.png differ
diff --git a/static/img/tutorial/graphql/02-query-results.png b/static/img/tutorial/graphql/02-query-results.png
new file mode 100644
index 0000000..5cd9913
Binary files /dev/null and b/static/img/tutorial/graphql/02-query-results.png differ
diff --git a/static/img/tutorial/graphql/03-nested-query-results.png b/static/img/tutorial/graphql/03-nested-query-results.png
new file mode 100644
index 0000000..7d22e06
Binary files /dev/null and b/static/img/tutorial/graphql/03-nested-query-results.png differ