diff --git a/README.md b/README.md
index d572ff3..8bd489f 100644
--- a/README.md
+++ b/README.md
@@ -77,7 +77,6 @@ are ) in the codebase, as of the last time that I updated this list.
   - debatable whether to make them a `def` right on the class or have the def be defined somewhere and just attach it like other fields
 - Fields that are "HoleType" are not supported and I don't even know what that means
 - IN case statements, the following patterns are not supported:
-  - List patterns
   - Concatenate patterns
   - Bitstring patterns (bytes)
 - Destructuring in assignments is not supported yet
@@ -85,7 +84,7 @@ are ) in the codebase, as of the last time that I updated this list.
   - other structures will maybe need a match statement?
 - Use statements are not supported yet
 
-### Some other the things I know are missing
+### Some other things I know are missing
 
 - empty tuples are probably broken
   - (EASY) I used parens instead of a `,` like a total python NOOB
diff --git a/src/compiler/internal/generator/statements.gleam b/src/compiler/internal/generator/statements.gleam
index 740ba72..e8768b8 100644
--- a/src/compiler/internal/generator/statements.gleam
+++ b/src/compiler/internal/generator/statements.gleam
@@ -94,6 +94,7 @@ fn generate_pattern(pattern: python.Pattern) -> StringBuilder {
       |> string_builder.join(", ")
       |> string_builder.prepend("(")
       |> string_builder.append(")")
+    python.PatternList(elements, rest) -> generate_pattern_list(elements, rest)
     python.PatternAlternate(patterns) ->
       patterns
       |> list.map(generate_pattern)
@@ -123,3 +124,21 @@ fn generate_pattern_constructor_field(
     python.UnlabelledField(pattern) -> generate_pattern(pattern)
   }
 }
+
+/// Lists are weird. Gleam syntax is like [a, b, c, ..rest]
+/// But the pattern in python has to match a linked list.
+/// The pattern is essentially GleamList(a, GleamList(b, GleamList(c, rest)))
+/// potential optimization: make tail recursive by carrying the number of
+/// closing parenns forward
+fn generate_pattern_list(elements, rest) -> StringBuilder {
+  case elements, rest {
+    [], option.None -> string_builder.from_string("None")
+    [], option.Some(pattern) -> generate_pattern(pattern)
+    [head, ..others], rest ->
+      string_builder.from_string("GleamList(")
+      |> string_builder.append_builder(generate_pattern(head))
+      |> string_builder.append(", ")
+      |> string_builder.append_builder(generate_pattern_list(others, rest))
+      |> string_builder.append(")")
+  }
+}
diff --git a/src/compiler/internal/transformer/patterns.gleam b/src/compiler/internal/transformer/patterns.gleam
index f2789cc..9a79030 100644
--- a/src/compiler/internal/transformer/patterns.gleam
+++ b/src/compiler/internal/transformer/patterns.gleam
@@ -42,7 +42,11 @@ fn transform_pattern(pattern: glance.Pattern) -> python.Pattern {
     glance.PatternDiscard(str) -> python.PatternVariable("_" <> str)
     glance.PatternTuple(patterns) ->
       python.PatternTuple(list.map(patterns, transform_pattern))
-    glance.PatternList(_, _) -> todo as "list patterns are not supported yet"
+    glance.PatternList(elems, rest) ->
+      python.PatternList(
+        list.map(elems, transform_pattern),
+        option.map(rest, transform_pattern),
+      )
     glance.PatternAssignment(pattern, name) ->
       python.PatternAssignment(transform_pattern(pattern), name)
     glance.PatternConcatenate(_, _) ->
diff --git a/src/compiler/python.gleam b/src/compiler/python.gleam
index 6772d6a..582ee6b 100644
--- a/src/compiler/python.gleam
+++ b/src/compiler/python.gleam
@@ -118,6 +118,7 @@ pub type Pattern {
   PatternVariable(value: String)
   PatternAssignment(pattern: Pattern, name: String)
   PatternTuple(value: List(Pattern))
+  PatternList(elems: List(Pattern), rest: option.Option(Pattern))
   PatternAlternate(patterns: List(Pattern))
   PatternConstructor(
     module: option.Option(String),
diff --git a/src/python_prelude.gleam b/src/python_prelude.gleam
index 104c99a..a8022ee 100644
--- a/src/python_prelude.gleam
+++ b/src/python_prelude.gleam
@@ -1,4 +1,5 @@
 pub const gleam_builtins = "
+from __future__ import annotations
 import dataclasses
 import sys
 import typing
@@ -12,36 +13,29 @@ GleamListElem = typing.TypeVar('GleamListElem')
 
 
 class GleamList(typing.Generic[GleamListElem]):
+    __slots__ = [\"value\", \"tail\"]
+    __match_args__ = (\"value\", \"tail\")
+
+    def __init__(self, value: GleamListElem, tail: GleamList[GleamListElem] | None):
+        self.value = value
+        self.tail = tail
+
     def __str__(self):
         strs = []
         head = self
 
-        while not head.is_empty:
-            strs.append(head.value)
+        while head is not None:
+            strs.append(str(head.value))
             head = head.tail
 
-        return  'GleamList([' + ', '.join(strs) + '])'
-
-
-class NonEmptyGleamList(GleamList[GleamListElem]):
-    __slots__ = ['value', 'tail']
-    is_empty = False
-
-    def __init__(self, value: GleamListElem, tail: GleamList[GleamListElem]):
-        self.value = value
-        self.tail = tail
-
-
-class EmptyGleamList(GleamList):
-    __slots__ = []
-    is_empty = True
+        return \"GleamList([\" + \", \".join(strs) + \"])\"
 
 
 
-def to_gleam_list(elements: list[GleamListElem], tail: GleamList = EmptyGleamList()):
+def to_gleam_list(elements: list[GleamListElem], tail: GleamList | None=None):
     head = tail
     for element in reversed(elements):
-        head = NonEmptyGleamList(element, head)
+        head = GleamList(element, head)
     return head
 
 def gleam_bitstring_segments_to_bytes(*segments):
diff --git a/test/case_test.gleam b/test/case_test.gleam
index 1958d3e..7a586bb 100644
--- a/test/case_test.gleam
+++ b/test/case_test.gleam
@@ -216,3 +216,152 @@ def main():
     return _fn_case_0(1)",
   )
 }
+
+pub fn case_empty_list_test() {
+  "pub fn main() {
+    case [] {
+      [] -> 1
+    }
+  }
+  "
+  |> compiler.compile
+  |> should.be_ok
+  |> should.equal(
+    "from gleam_builtins import *
+
+def main():
+    def _fn_case_0(_case_subject):
+        match _case_subject:
+            case None:
+                return 1
+    return _fn_case_0(to_gleam_list([]))",
+  )
+}
+
+pub fn case_single_element_list_test() {
+  "pub fn main() {
+    case [1] {
+      [1] -> 1
+    }
+  }
+  "
+  |> compiler.compile
+  |> should.be_ok
+  |> should.equal(
+    "from gleam_builtins import *
+
+def main():
+    def _fn_case_0(_case_subject):
+        match _case_subject:
+            case GleamList(1, None):
+                return 1
+    return _fn_case_0(to_gleam_list([1]))",
+  )
+}
+
+pub fn case_multi_element_list_test() {
+  "pub fn main() {
+    case [1, 2, 3] {
+      [1, 2, 3] -> 1
+    }
+  }
+  "
+  |> compiler.compile
+  |> should.be_ok
+  |> should.equal(
+    "from gleam_builtins import *
+
+def main():
+    def _fn_case_0(_case_subject):
+        match _case_subject:
+            case GleamList(1, GleamList(2, GleamList(3, None))):
+                return 1
+    return _fn_case_0(to_gleam_list([1, 2, 3]))",
+  )
+}
+
+// The gleam formatter doesn't permit this scenario, but it is encountered
+// during recursion
+pub fn case_empty_rest_case_test() {
+  "pub fn main() {
+    case [1, 2, 3] {
+      rest -> 1
+    }
+  }
+  "
+  |> compiler.compile
+  |> should.be_ok
+  |> should.equal(
+    "from gleam_builtins import *
+
+def main():
+    def _fn_case_0(_case_subject):
+        match _case_subject:
+            case rest:
+                return 1
+    return _fn_case_0(to_gleam_list([1, 2, 3]))",
+  )
+}
+
+pub fn single_element_with_rest_case_test() {
+  "pub fn main() {
+    case [1, 2, 3] {
+      [1, ..rest] -> 1
+    }
+  }
+  "
+  |> compiler.compile
+  |> should.be_ok
+  |> should.equal(
+    "from gleam_builtins import *
+
+def main():
+    def _fn_case_0(_case_subject):
+        match _case_subject:
+            case GleamList(1, rest):
+                return 1
+    return _fn_case_0(to_gleam_list([1, 2, 3]))",
+  )
+}
+
+pub fn multi_element_with_rest_case_test() {
+  "pub fn main() {
+    case [1, 2, 3] {
+      [1, 2, ..rest] -> 1
+    }
+  }
+  "
+  |> compiler.compile
+  |> should.be_ok
+  |> should.equal(
+    "from gleam_builtins import *
+
+def main():
+    def _fn_case_0(_case_subject):
+        match _case_subject:
+            case GleamList(1, GleamList(2, rest)):
+                return 1
+    return _fn_case_0(to_gleam_list([1, 2, 3]))",
+  )
+}
+
+pub fn unnamed_rest_test() {
+  "pub fn main() {
+    case [1, 2, 3] {
+      [1, 2, ..] -> 1
+    }
+  }
+  "
+  |> compiler.compile
+  |> should.be_ok
+  |> should.equal(
+    "from gleam_builtins import *
+
+def main():
+    def _fn_case_0(_case_subject):
+        match _case_subject:
+            case GleamList(1, GleamList(2, _)):
+                return 1
+    return _fn_case_0(to_gleam_list([1, 2, 3]))",
+  )
+}