diff --git a/lib/elixir/pages/getting-started/alias-require-and-import.md b/lib/elixir/pages/getting-started/alias-require-and-import.md
new file mode 100644
index 0000000000..229ffab35b
--- /dev/null
+++ b/lib/elixir/pages/getting-started/alias-require-and-import.md
@@ -0,0 +1,239 @@
+# alias, require, and import
+
+In order to facilitate software reuse, Elixir provides three directives (`alias`, `require` and `import`) plus a macro called `use` summarized below:
+
+```elixir
+# Alias the module so it can be called as Bar instead of Foo.Bar
+alias Foo.Bar, as: Bar
+
+# Require the module in order to use its macros
+require Foo
+
+# Import functions from Foo so they can be called without the `Foo.` prefix
+import Foo
+
+# Invokes the custom code defined in Foo as an extension point
+use Foo
+```
+
+We are going to explore them in detail now. Keep in mind the first three are called directives because they have *lexical scope*, while `use` is a common extension point that allows the used module to inject code.
+
+## alias
+
+`alias` allows you to set up aliases for any given module name.
+
+Imagine a module uses a specialized list implemented in `Math.List`. The `alias` directive allows referring to `Math.List` just as `List` within the module definition:
+
+```elixir
+defmodule Stats do
+ alias Math.List, as: List
+ # In the remaining module definition List expands to Math.List.
+end
+```
+
+The original `List` can still be accessed within `Stats` by the fully-qualified name `Elixir.List`.
+
+> All modules defined in Elixir are defined inside the main `Elixir` namespace, such as `Elixir.String`. However, for convenience, you can omit "Elixir." when referencing them.
+
+Aliases are frequently used to define shortcuts. In fact, calling `alias` without an `:as` option sets the alias automatically to the last part of the module name, for example:
+
+```elixir
+alias Math.List
+```
+
+Is the same as:
+
+```elixir
+alias Math.List, as: List
+```
+
+Note that `alias` is *lexically scoped*, which allows you to set aliases inside specific functions:
+
+```elixir
+defmodule Math do
+ def plus(a, b) do
+ alias Math.List
+ # ...
+ end
+
+ def minus(a, b) do
+ # ...
+ end
+end
+```
+
+In the example above, since we are invoking `alias` inside the function `plus/2`, the alias will be valid only inside the function `plus/2`. `minus/2` won't be affected at all.
+
+## require
+
+Elixir provides macros as a mechanism for meta-programming (writing code that generates code). Macros are expanded at compile time.
+
+Public functions in modules are globally available, but in order to use macros, you need to opt-in by requiring the module they are defined in.
+
+```elixir
+iex> Integer.is_odd(3)
+** (UndefinedFunctionError) function Integer.is_odd/1 is undefined or private. However, there is a macro with the same name and arity. Be sure to require Integer if you intend to invoke this macro
+ (elixir) Integer.is_odd(3)
+iex> require Integer
+Integer
+iex> Integer.is_odd(3)
+true
+```
+
+In Elixir, `Integer.is_odd/1` is defined as a macro so that it can be used as a guard. This means that, in order to invoke `Integer.is_odd/1`, we need to first require the `Integer` module.
+
+Note that like the `alias` directive, `require` is also lexically scoped. We will talk more about macros in a later chapter.
+
+## import
+
+We use `import` whenever we want to access functions or macros from other modules without using the fully-qualified name. Note we can only import public functions, as private functions are never accessible externally.
+
+For example, if we want to use the `duplicate/2` function from the `List` module several times, we can import it:
+
+```elixir
+iex> import List, only: [duplicate: 2]
+List
+iex> duplicate(:ok, 3)
+[:ok, :ok, :ok]
+```
+
+We imported only the function `duplicate` (with arity 2) from `List`. Although `:only` is optional, its usage is recommended in order to avoid importing all the functions of a given module inside the current scope. `:except` could also be given as an option in order to import everything in a module except a list of functions.
+
+Note that `import` is *lexically scoped* too. This means that we can import specific macros or functions inside function definitions:
+
+```elixir
+defmodule Math do
+ def some_function do
+ import List, only: [duplicate: 2]
+ duplicate(:ok, 10)
+ end
+end
+```
+
+In the example above, the imported `List.duplicate/2` is only visible within that specific function. `duplicate/2` won't be available in any other function in that module (or any other module for that matter).
+
+Note that `import`s are generally discouraged in the language. When working on your own code, prefer `alias` to `import`.
+
+## use
+
+The `use` macro is frequently used as an extension point. This means that, when you `use` a module `FooBar`, you allow that module to inject *any* code in the current module, such as importing itself or other modules, defining new functions, setting a module state, etc.
+
+For example, in order to write tests using the ExUnit framework, a developer should use the `ExUnit.Case` module:
+
+```elixir
+defmodule AssertionTest do
+ use ExUnit.Case, async: true
+
+ test "always pass" do
+ assert true
+ end
+end
+```
+
+Behind the scenes, `use` requires the given module and then calls the `__using__/1` callback on it allowing the module to inject some code into the current context. Some modules (for example, the above `ExUnit.Case`, but also `Supervisor` and `GenServer`) use this mechanism to populate your module with some basic behaviour, which your module is intended to override or complete.
+
+Generally speaking, the following module:
+
+```elixir
+defmodule Example do
+ use Feature, option: :value
+end
+```
+
+is compiled into
+
+```elixir
+defmodule Example do
+ require Feature
+ Feature.__using__(option: :value)
+end
+```
+
+Since `use` allows any code to run, we can't really know the side-effects of using a module without reading its documentation. Therefore use this function with care and only if strictly required. Don't use `use` where an `import` or `alias` would do.
+
+## Understanding Aliases
+
+At this point, you may be wondering: what exactly is an Elixir alias and how is it represented?
+
+An alias in Elixir is a capitalized identifier (like `String`, `Keyword`, etc) which is converted to an atom during compilation. For instance, the `String` alias translates by default to the atom `:"Elixir.String"`:
+
+```elixir
+iex> is_atom(String)
+true
+iex> to_string(String)
+"Elixir.String"
+iex> :"Elixir.String" == String
+true
+```
+
+By using the `alias/2` directive, we are changing the atom the alias expands to.
+
+Aliases expand to atoms because in the Erlang VM (and consequently Elixir) modules are always represented by atoms:
+
+```elixir
+iex> List.flatten([1, [2], 3])
+[1, 2, 3]
+iex> :"Elixir.List".flatten([1, [2], 3])
+[1, 2, 3]
+```
+
+That's the mechanism we use to call Erlang modules:
+
+```elixir
+iex> :lists.flatten([1, [2], 3])
+[1, 2, 3]
+```
+
+## Module nesting
+
+Now that we have talked about aliases, we can talk about nesting and how it works in Elixir. Consider the following example:
+
+```elixir
+defmodule Foo do
+ defmodule Bar do
+ end
+end
+```
+
+The example above will define two modules: `Foo` and `Foo.Bar`. The second can be accessed as `Bar` inside `Foo` as long as they are in the same lexical scope.
+
+If, later, the `Bar` module is moved outside the `Foo` module definition, it must be referenced by its full name (`Foo.Bar`) or an alias must be set using the `alias` directive discussed above.
+
+**Note**: in Elixir, you don't have to define the `Foo` module before being able to define the `Foo.Bar` module, as they are effectively independent. The above could also be written as:
+
+```elixir
+defmodule Foo.Bar do
+end
+
+defmodule Foo do
+ alias Foo.Bar
+ # Can still access it as `Bar`
+end
+```
+
+Aliasing a nested module does not bring parent modules into scope. Consider the following example:
+
+```elixir
+defmodule Foo do
+ defmodule Bar do
+ defmodule Baz do
+ end
+ end
+end
+
+alias Foo.Bar.Baz
+# The module `Foo.Bar.Baz` is now available as `Baz`
+# However, the module `Foo.Bar` is *not* available as `Bar`
+```
+
+As we will see in later chapters, aliases also play a crucial role in macros, to guarantee they are hygienic.
+
+## Multi alias/import/require/use
+
+It is possible to `alias`, `import`, `require`, or `use` multiple modules at once. This is particularly useful once we start nesting modules, which is very common when building Elixir applications. For example, imagine you have an application where all modules are nested under `MyApp`, you can alias the modules `MyApp.Foo`, `MyApp.Bar` and `MyApp.Baz` at once as follows:
+
+```elixir
+alias MyApp.{Foo, Bar, Baz}
+```
+
+With this, we have finished our tour of Elixir modules. The next topic to cover is module attributes.
diff --git a/lib/elixir/pages/getting-started/module-attributes.md b/lib/elixir/pages/getting-started/module-attributes.md
new file mode 100644
index 0000000000..3a67862495
--- /dev/null
+++ b/lib/elixir/pages/getting-started/module-attributes.md
@@ -0,0 +1,184 @@
+# Module attributes
+
+Module attributes in Elixir serve three purposes:
+
+1. They serve to annotate the module, often with information to be used by the user or the VM.
+2. They work as constants.
+3. They work as a temporary module storage to be used during compilation.
+
+Let's check each case, one by one.
+
+## As annotations
+
+Elixir brings the concept of module attributes from Erlang. For example:
+
+```elixir
+defmodule MyServer do
+ @moduledoc "My server code."
+end
+```
+
+In the example above, we are defining the module documentation by using the module attribute syntax. Elixir has a handful of reserved attributes. Here are a few of them, the most commonly used ones:
+
+* `@moduledoc` - provides documentation for the current module.
+* `@doc` - provides documentation for the function or macro that follows the attribute.
+* `@spec` - provides a typespec for the function that follows the attribute.
+* `@behaviour` - (notice the British spelling) used for specifying an OTP or user-defined behaviour.
+
+`@moduledoc` and `@doc` are by far the most used attributes, and we expect you to use them a lot. Elixir treats documentation as first-class and provides many functions to access documentation. We will cover them [in their own chapter](../references/writing-documentation.md).
+
+Let's go back to the `Math` module defined in the previous chapters, add some documentation and save it to the `math.ex` file:
+
+```elixir
+defmodule Math do
+ @moduledoc """
+ Provides math-related functions.
+
+ ## Examples
+
+ iex> Math.sum(1, 2)
+ 3
+
+ """
+
+ @doc """
+ Calculates the sum of two numbers.
+ """
+ def sum(a, b), do: a + b
+end
+```
+
+Elixir promotes the use of Markdown with heredocs to write readable documentation. Heredocs are multi-line strings, they start and end with triple double-quotes, keeping the formatting of the inner text. We can access the documentation of any compiled module directly from IEx:
+
+```console
+$ elixirc math.ex
+$ iex
+```
+
+```elixir
+iex> h Math # Access the docs for the module Math
+...
+iex> h Math.sum # Access the docs for the sum function
+...
+```
+
+We also provide a tool called [ExDoc](https://github.com/elixir-lang/ex_doc) which is used to generate HTML pages from the documentation.
+
+You can take a look at the docs for `Module` for a complete list of supported attributes. Elixir also uses attributes to define [typespecs](typespecs-and-behaviours.md), which will be explored later.
+
+## As "constants"
+
+Elixir developers often use module attributes when they wish to make a value more visible or reusable:
+
+```elixir
+defmodule MyServer do
+ @initial_state %{host: "127.0.0.1", port: 3456}
+ IO.inspect @initial_state
+end
+```
+
+Trying to access an attribute that was not defined will print a warning:
+
+```elixir
+defmodule MyServer do
+ @unknown
+end
+warning: undefined module attribute @unknown, please remove access to @unknown or explicitly set it before access
+```
+
+Attributes can also be read inside functions:
+
+```elixir
+defmodule MyServer do
+ @my_data 14
+ def first_data, do: @my_data
+ @my_data 13
+ def second_data, do: @my_data
+end
+
+MyServer.first_data #=> 14
+MyServer.second_data #=> 13
+```
+
+> Do not add a newline between the attribute and its value, otherwise Elixir will assume you are reading the value, rather than setting it.
+
+Functions may be called when defining a module attribute:
+
+```elixir
+defmodule MyApp.Status do
+ @service URI.parse("https://example.com")
+ def status(email) do
+ SomeHttpClient.get(@service)
+ end
+end
+```
+
+The function above will be called at compilation time and its *return value*, not the function call itself, is what will be substituted in for the attribute. So the above will effectively compile to this:
+
+```elixir
+defmodule MyApp.Status do
+ def status(email) do
+ SomeHttpClient.get(%URI{
+ authority: "example.com",
+ host: "example.com",
+ port: 443,
+ scheme: "https"
+ })
+ end
+end
+```
+
+This can be useful for pre-computing constant values, but it can also cause problems if you're expecting the function to be called at runtime. For example, if you are reading a value from a database or an environment variable inside an attribute, be aware that it will read that value only at compilation time. However, note you cannot invoke functions defined in the same module as part of the attribute itself, as those functions have not yet been defined.
+
+Every time an attribute is read inside a function, Elixir takes a snapshot of its current value. Therefore if you read the same attribute multiple times inside multiple functions, you may end-up making multiple copies of it. That's usually not an issue, but if you are using functions to compute large module attributes, that can slow down compilation. The solution is to move the attribute to shared function. For example, instead of this:
+
+```elixir
+def some_function, do: do_something_with(@example)
+def another_function, do: do_something_else_with(@example)
+```
+
+Prefer this:
+
+```elixir
+def some_function, do: do_something_with(example())
+def another_function, do: do_something_else_with(example())
+defp example, do: @example
+```
+
+If `@example` is cheap to compute, it may be even better to skip the module attribute altogether, and compute its value inside the function.
+
+### Accumulating attributes
+
+Normally, repeating a module attribute will cause its value to be reassigned, but there are circumstances where you may want to [configure the module attribute](`Module.register_attribute/3`) so that its values are accumulated:
+
+```elixir
+defmodule Foo do
+ Module.register_attribute(__MODULE__, :param, accumulate: true)
+
+ @param :foo
+ @param :bar
+ # here @param == [:bar, :foo]
+end
+```
+
+## As temporary storage
+
+To see an example of using module attributes as storage, look no further than Elixir's unit test framework called `ExUnit`. ExUnit uses module attributes for multiple different purposes:
+
+```elixir
+defmodule MyTest do
+ use ExUnit.Case, async: true
+
+ @tag :external
+ @tag os: :unix
+ test "contacts external service" do
+ # ...
+ end
+end
+```
+
+In the example above, `ExUnit` stores the value of `async: true` in a module attribute to change how the module is compiled. Tags are also defined as `accumulate: true` attributes, and they store tags that can be used to setup and filter tests. For example, you can avoid running external tests on your machine because they are slow and dependent on other services, while they can still be enabled in your build system.
+
+In order to understand the underlying code, we'd need macros, so we will revisit this pattern in the meta-programming guide and learn how to use module attributes as storage to allow developers to create Domain Specific Languages (DSLs).
+
+In the next chapters, we'll explore structs and protocols before moving to exception handling and other constructs like sigils and comprehensions.
diff --git a/lib/elixir/pages/getting-started/protocols.md b/lib/elixir/pages/getting-started/protocols.md
new file mode 100644
index 0000000000..e72620aed6
--- /dev/null
+++ b/lib/elixir/pages/getting-started/protocols.md
@@ -0,0 +1,256 @@
+# Protocols
+
+Protocols are a mechanism to achieve polymorphism in Elixir where you want the behaviour to vary depending on the data type. We are already familiar with one way of solving this type of problem: via pattern matching and guard clauses. Consider a simple utility module that would tell us the type of input variable:
+
+```elixir
+defmodule Utility do
+ def type(value) when is_binary(value), do: "string"
+ def type(value) when is_integer(value), do: "integer"
+ # ... other implementations ...
+end
+```
+
+If the use of this module were confined to your own project, you would be able to keep defining new `type/1` functions for each new data type. However, this code could be problematic if it was shared as a dependency by multiple apps because there would be no easy way to extend its functionality.
+
+This is where protocols can help us: protocols allow us to extend the original behaviour for as many data types as we need. That's because **dispatching on a protocol is available to any data type that has implemented the protocol** and a protocol can be implemented by anyone, at any time.
+
+Here's how we could write the same `Utility.type/1` functionality as a protocol:
+
+```elixir
+defprotocol Utility do
+ @spec type(t) :: String.t()
+ def type(value)
+end
+
+defimpl Utility, for: BitString do
+ def type(_value), do: "string"
+end
+
+defimpl Utility, for: Integer do
+ def type(_value), do: "integer"
+end
+```
+
+We define the protocol using `defprotocol/2` - its functions and specs may look similar to interfaces or abstract base classes in other languages. We can add as many implementations as we like using `defimpl/2`. The output is exactly the same as if we had a single module with multiple functions:
+
+```elixir
+iex> Utility.type("foo")
+"string"
+iex> Utility.type(123)
+"integer"
+```
+
+With protocols, however, we are no longer stuck having to continuously modify the same module to support more and more data types. For example, we could spread the `defimpl` calls above over multiple files and Elixir will dispatch the execution to the appropriate implementation based on the data type. Functions defined in a protocol may have more than one input, but the **dispatching will always be based on the data type of the first input**.
+
+One of the most common protocols you may encounter is the `String.Chars` protocol: implementing its `to_string/1` function for your custom structs will tell the Elixir kernel how to represent them as strings. We will explore all built-in protocols later. For now, let's implement our own.
+
+## Example
+
+Now that you have seen an example of the type of problem protocols help solve and how they solve them, let's look at a more in-depth example.
+
+In Elixir, we have two idioms for checking how many items there are in a data structure: `length` and `size`. `length` means the information must be computed. For example, `length(list)` needs to traverse the whole list to calculate its length. On the other hand, `tuple_size(tuple)` and `byte_size(binary)` do not depend on the tuple and binary size as the size information is pre-computed in the data structure.
+
+Even if we have type-specific functions for getting the size built into Elixir (such as `tuple_size/1`), we could implement a generic `Size` protocol that all data structures for which size is pre-computed would implement.
+
+The protocol definition would look like this:
+
+```elixir
+defprotocol Size do
+ @doc "Calculates the size (and not the length!) of a data structure"
+ def size(data)
+end
+```
+
+The `Size` protocol expects a function called `size` that receives one argument (the data structure we want to know the size of) to be implemented. We can now implement this protocol for the data structures that would have a compliant implementation:
+
+```elixir
+defimpl Size, for: BitString do
+ def size(string), do: byte_size(string)
+end
+
+defimpl Size, for: Map do
+ def size(map), do: map_size(map)
+end
+
+defimpl Size, for: Tuple do
+ def size(tuple), do: tuple_size(tuple)
+end
+```
+
+We didn't implement the `Size` protocol for lists as there is no "size" information pre-computed for lists, and the length of a list has to be computed (with `length/1`).
+
+Now with the protocol defined and implementations in hand, we can start using it:
+
+```elixir
+iex> Size.size("foo")
+3
+iex> Size.size({:ok, "hello"})
+2
+iex> Size.size(%{label: "some label"})
+1
+```
+
+Passing a data type that doesn't implement the protocol raises an error:
+
+```elixir
+iex> Size.size([1, 2, 3])
+** (Protocol.UndefinedError) protocol Size not implemented for [1, 2, 3] of type List
+```
+
+It's possible to implement protocols for all Elixir data types:
+
+* `Atom`
+* `BitString`
+* `Float`
+* `Function`
+* `Integer`
+* `List`
+* `Map`
+* `PID`
+* `Port`
+* `Reference`
+* `Tuple`
+
+## Protocols and structs
+
+The power of Elixir's extensibility comes when protocols and structs are used together.
+
+In the [previous chapter](structs.md), we have learned that although structs are maps, they do not share protocol implementations with maps. For example, `MapSet`s (sets based on maps) are implemented as structs. Let's try to use the `Size` protocol with a `MapSet`:
+
+```elixir
+iex> Size.size(%{})
+0
+iex> set = %MapSet{} = MapSet.new
+MapSet.new([])
+iex> Size.size(set)
+** (Protocol.UndefinedError) protocol Size not implemented for MapSet.new([]) of type MapSet (a struct)
+```
+
+Instead of sharing protocol implementation with maps, structs require their own protocol implementation. Since a `MapSet` has its size precomputed and accessible through `MapSet.size/1`, we can define a `Size` implementation for it:
+
+```elixir
+defimpl Size, for: MapSet do
+ def size(set), do: MapSet.size(set)
+end
+```
+
+If desired, you could come up with your own semantics for the size of your struct. Not only that, you could use structs to build more robust data types, like queues, and implement all relevant protocols, such as `Enumerable` and possibly `Size`, for this data type.
+
+```elixir
+defmodule User do
+ defstruct [:name, :age]
+end
+
+defimpl Size, for: User do
+ def size(_user), do: 2
+end
+```
+
+## Implementing `Any`
+
+Manually implementing protocols for all types can quickly become repetitive and tedious. In such cases, Elixir provides two options: we can explicitly derive the protocol implementation for our types or automatically implement the protocol for all types. In both cases, we need to implement the protocol for `Any`.
+
+### Deriving
+
+Elixir allows us to derive a protocol implementation based on the `Any` implementation. Let's first implement `Any` as follows:
+
+```elixir
+defimpl Size, for: Any do
+ def size(_), do: 0
+end
+```
+
+The implementation above is arguably not a reasonable one. For example, it makes no sense to say that the size of a `PID` or an `Integer` is `0`.
+
+However, we should be fine with the implementation for `Any`, in order to use such implementation we would need to tell our struct to explicitly derive the `Size` protocol:
+
+```elixir
+defmodule OtherUser do
+ @derive [Size]
+ defstruct [:name, :age]
+end
+```
+
+When deriving, Elixir will implement the `Size` protocol for `OtherUser` based on the implementation provided for `Any`.
+
+### Fallback to `Any`
+
+Another alternative to `@derive` is to explicitly tell the protocol to fallback to `Any` when an implementation cannot be found. This can be achieved by setting `@fallback_to_any` to `true` in the protocol definition:
+
+```elixir
+defprotocol Size do
+ @fallback_to_any true
+ def size(data)
+end
+```
+
+As we said in the previous section, the implementation of `Size` for `Any` is not one that can apply to any data type. That's one of the reasons why `@fallback_to_any` is an opt-in behaviour. For the majority of protocols, raising an error when a protocol is not implemented is the proper behaviour. That said, assuming we have implemented `Any` as in the previous section:
+
+```elixir
+defimpl Size, for: Any do
+ def size(_), do: 0
+end
+```
+
+Now all data types (including structs) that have not implemented the `Size` protocol will be considered to have a size of `0`.
+
+Which technique is best between deriving and falling back to `Any` depends on the use case but, given Elixir developers prefer explicit over implicit, you may see many libraries pushing towards the `@derive` approach.
+
+## Built-in protocols
+
+Elixir ships with some built-in protocols. In previous chapters, we have discussed the `Enum` module which provides many functions that work with any data structure that implements the `Enumerable` protocol:
+
+```elixir
+iex> Enum.map([1, 2, 3], fn x -> x * 2 end)
+[2, 4, 6]
+iex> Enum.reduce(1..3, 0, fn x, acc -> x + acc end)
+6
+```
+
+Another useful example is the `String.Chars` protocol, which specifies how to convert a data structure to its human representation as a string. It's exposed via the `to_string` function:
+
+```elixir
+iex> to_string(:hello)
+"hello"
+```
+
+Notice that string interpolation in Elixir calls the `to_string` function:
+
+```elixir
+iex> "age: #{25}"
+"age: 25"
+```
+
+The snippet above only works because numbers implement the `String.Chars` protocol. Passing a tuple, for example, will lead to an error:
+
+```elixir
+iex> tuple = {1, 2, 3}
+{1, 2, 3}
+iex> "tuple: #{tuple}"
+** (Protocol.UndefinedError) protocol String.Chars not implemented for {1, 2, 3} of type Tuple
+```
+
+When there is a need to "print" a more complex data structure, one can use the `inspect` function, based on the `Inspect` protocol:
+
+```elixir
+iex> "tuple: #{inspect(tuple)}"
+"tuple: {1, 2, 3}"
+```
+
+The `Inspect` protocol is the protocol used to transform any data structure into a readable textual representation. This is what tools like IEx use to print results:
+
+```elixir
+iex> {1, 2, 3}
+{1, 2, 3}
+iex> %User{}
+%User{name: "john", age: 27}
+```
+
+Keep in mind that, by convention, whenever the inspected value starts with `#`, it is representing a data structure in non-valid Elixir syntax. This means the inspect protocol is not reversible as information may be lost along the way:
+
+```elixir
+iex> inspect &(&1+2)
+"#Function<6.71889879/1 in :erl_eval.expr/5>"
+```
+
+There are other protocols in Elixir but this covers the most common ones. You can learn more about protocols and implementations in the `Protocol` module.
diff --git a/lib/elixir/pages/getting-started/structs.md b/lib/elixir/pages/getting-started/structs.md
new file mode 100644
index 0000000000..534c07884c
--- /dev/null
+++ b/lib/elixir/pages/getting-started/structs.md
@@ -0,0 +1,140 @@
+# Structs
+
+We learned about maps [in earlier chapters](keywords-and-maps.md):
+
+```elixir
+iex> map = %{a: 1, b: 2}
+%{a: 1, b: 2}
+iex> map[:a]
+1
+iex> %{map | a: 3}
+%{a: 3, b: 2}
+```
+
+Structs are extensions built on top of maps that provide compile-time checks and default values.
+
+## Defining structs
+
+To define a struct, the `defstruct/1` construct is used:
+
+```elixir
+iex> defmodule User do
+...> defstruct name: "John", age: 27
+...> end
+```
+
+The keyword list used with `defstruct` defines what fields the struct will have along with their default values. Structs take the name of the module they're defined in. In the example above, we defined a struct named `User`.
+
+We can now create `User` structs by using a syntax similar to the one used to create maps:
+
+```elixir
+iex> %User{}
+%User{age: 27, name: "John"}
+iex> %User{name: "Jane"}
+%User{age: 27, name: "Jane"}
+```
+
+Structs provide *compile-time* guarantees that only the fields defined through `defstruct` will be allowed to exist in a struct:
+
+```elixir
+iex> %User{oops: :field}
+** (KeyError) key :oops not found expanding struct: User.__struct__/1
+```
+
+## Accessing and updating structs
+
+Structs share the same syntax for accessing and updating fields as maps of fixed keys:
+
+```elixir
+iex> john = %User{}
+%User{age: 27, name: "John"}
+iex> john.name
+"John"
+iex> jane = %{john | name: "Jane"}
+%User{age: 27, name: "Jane"}
+iex> %{jane | oops: :field}
+** (KeyError) key :oops not found in: %User{age: 27, name: "Jane"}
+```
+
+When using the update syntax (`|`), Elixir is aware that no new keys will be added to the struct, allowing the maps underneath to share their structure in memory. In the example above, both `john` and `jane` share the same key structure in memory.
+
+Structs can also be used in pattern matching, both for matching on the value of specific keys as well as for ensuring that the matching value is a struct of the same type as the matched value.
+
+```elixir
+iex> %User{name: name} = john
+%User{age: 27, name: "John"}
+iex> name
+"John"
+iex> %User{} = %{}
+** (MatchError) no match of right hand side value: %{}
+```
+
+## Structs are bare maps underneath
+
+Structs are simply maps with a "special" field named `__struct__` that holds the name of the struct:
+
+```elixir
+iex> is_map(john)
+true
+iex> john.__struct__
+User
+```
+
+However, structs do not inherit any of the protocols that maps do. For example, you can neither enumerate nor access a struct:
+
+```elixir
+iex> john = %User{}
+%User{age: 27, name: "John"}
+iex> john[:name]
+** (UndefinedFunctionError) function User.fetch/2 is undefined (User does not implement the Access behaviour)
+ User.fetch(%User{age: 27, name: "John"}, :name)
+iex> Enum.each(john, fn {field, value} -> IO.puts(value) end)
+** (Protocol.UndefinedError) protocol Enumerable not implemented for %User{age: 27, name: "John"} of type User (a struct)
+```
+
+Structs alongside protocols provide one of the most important features for Elixir developers: data polymorphism. That's what we will explore in the next chapter.
+
+## Default values and required keys
+
+If you don't specify a default key value when defining a struct, `nil` will be assumed:
+
+```elixir
+iex> defmodule Product do
+...> defstruct [:name]
+...> end
+iex> %Product{}
+%Product{name: nil}
+```
+
+You can define a structure combining both fields with explicit default values, and implicit `nil` values. In this case you must first specify the fields which implicitly default to nil:
+
+```elixir
+iex> defmodule User do
+...> defstruct [:email, name: "John", age: 27]
+...> end
+iex> %User{}
+%User{age: 27, email: nil, name: "John"}
+```
+
+Doing it in reverse order will raise a syntax error:
+
+```elixir
+iex> defmodule User do
+...> defstruct [name: "John", age: 27, :email]
+...> end
+** (SyntaxError) iex:107: unexpected expression after keyword list. Keyword lists must always come last in lists and maps.
+```
+
+You can also enforce that certain keys have to be specified when creating the struct via the `@enforce_keys` module attribute:
+
+```elixir
+iex> defmodule Car do
+...> @enforce_keys [:make]
+...> defstruct [:model, :make]
+...> end
+iex> %Car{}
+** (ArgumentError) the following keys must also be given when building struct Car: [:make]
+ expanding struct: Car.__struct__/1
+```
+
+Enforcing keys provides a simple compile-time guarantee to aid developers when building structs. It is not enforced on updates and it does not provide any sort of value-validation.
diff --git a/lib/elixir/scripts/elixir_docs.exs b/lib/elixir/scripts/elixir_docs.exs
index 0812415fa9..af6edc17e9 100644
--- a/lib/elixir/scripts/elixir_docs.exs
+++ b/lib/elixir/scripts/elixir_docs.exs
@@ -16,6 +16,10 @@ canonical = System.fetch_env!("CANONICAL")
"lib/elixir/pages/getting-started/enumerable-and-streams.md",
"lib/elixir/pages/getting-started/processes.md",
"lib/elixir/pages/getting-started/io-and-the-file-system.md",
+ "lib/elixir/pages/getting-started/alias-require-and-import.md",
+ "lib/elixir/pages/getting-started/module-attributes.md",
+ "lib/elixir/pages/getting-started/structs.md",
+ "lib/elixir/pages/getting-started/protocols.md",
"lib/elixir/pages/anti-patterns/what-anti-patterns.md",
"lib/elixir/pages/anti-patterns/code-anti-patterns.md",
"lib/elixir/pages/anti-patterns/design-anti-patterns.md",