Question

Ruby include vs extend: Understanding Modules and Mixins

rubymoduleincludeextend

Question

I am learning Ruby metaprogramming and trying to understand how modules and mixins work.

From what I understand:

  • include adds a module's methods as instance methods to a class
  • extend adds a module's methods as class methods to a class

Is that the main difference, or is there more to it?

For example:

module ReusableModule
  def module_method
    puts "Module Method: Hi there!"
  end
end

class ClassThatIncludes
  include ReusableModule
end

class ClassThatExtends
  extend ReusableModule
end

puts "Include"
ClassThatIncludes.new.module_method

puts "Extend"
ClassThatExtends.module_method

Why does include make the method available on instances, while extend makes it available on the class itself?

Short Answer

By the end of this page, you will understand what include and extend do in Ruby, how they affect method lookup, why one adds instance methods and the other adds class-level behavior, and when to use each in real code.

Concept

Ruby modules are a way to group reusable behavior.

When you add a module to a class, the key question is: who should receive those methods?

  • With include, the module is inserted into the class's ancestor chain so its methods become available to instances of that class.
  • With extend, the module is added to a specific object's singleton class, so its methods become available to that object itself.

That is why this works differently for classes:

  • A class in Ruby is also an object
  • So when you extend SomeModule inside a class, you are adding methods to the class object, which appear as class methods

Why this matters

This distinction shows up everywhere in Ruby:

  • sharing behavior between instances of many classes
  • adding utility methods to a class
  • building DSLs
  • Rails concerns and macros
  • metaprogramming patterns

The short version is:

  • include = instances gain the module's methods
  • extend = the receiver itself gains the module's methods

So yes, your summary is mostly correct. The deeper idea is that extend is not specifically about class methods. It adds methods to any object you call it on. If that object happens to be a class, they look like class methods.

Mental Model

Think of a module as a toolkit.

  • include puts the toolkit into every worker created from a class
  • extend puts the toolkit directly into the factory itself

If CarFactory includes a module, then each car built by the factory can use those tools. If CarFactory extends a module, then the factory can use those tools directly.

Another way to see it:

  • include affects future instances
  • extend affects the current object

Since classes are objects in Ruby, extending a class means the class object gets those methods.

Take Quiz

Syntax and Examples

Core syntax

module MyModule
  def greet
    "Hello"
  end
end

class Person
  include MyModule
end

class Robot
  extend MyModule
end

Example: include

module Speakable
  def speak
    "I can speak"
  end
end

class Human
  include Speakable
end

person = Human.new
puts person.speak
# => I can speak

What happened?

  • Speakable defines an instance method: speak
  • Human includes the module
  • Every Human object can now call speak

Example: extend

module Identifiable
  def category
    "Machine"
  end
end

class Robot
  extend Identifiable
end

puts Robot.category
# => Machine

What happened?

  • Robot is an object of class Class
  • extend Identifiable adds category to the Robot object itself
  • So Robot.category works
  • But Robot.new.category would fail unless the module was also included

Same module, both behaviors

module Demo
  def hello
    "hello"
  end
end

class Example
  include Demo
  extend Demo
end

puts Example.hello
# => hello

puts Example.new.hello
# => hello

This class can use hello both as a class method and an instance method.

Step by Step Execution

Consider this code:

module ReusableModule
  def module_method
    "Module Method: Hi there!"
  end
end

class ClassThatIncludes
  include ReusableModule
end

class ClassThatExtends
  extend ReusableModule
end

Step-by-step

1. Ruby defines the module

module ReusableModule

Ruby creates a module object named ReusableModule.

2. The method is stored in the module

def module_method
  "Module Method: Hi there!"
end

This becomes an instance method of the module, ready to be mixed into something else.

3. ClassThatIncludes includes the module

class ClassThatIncludes
  include ReusableModule
end

Ruby inserts ReusableModule into the ancestor chain of ClassThatIncludes.

So when you call:

ClassThatIncludes.new.module_method

Ruby looks for module_method in this order:

  1. the instance
  2. ClassThatIncludes
  3. ReusableModule
  4. superclass chain

It finds the method in ReusableModule, so the instance can use it.

4. ClassThatExtends extends the module

class ClassThatExtends
  extend ReusableModule
end

Here, the receiver is the class object ClassThatExtends. Ruby adds the module to that object's singleton class.

So when you call:

ClassThatExtends.module_method

Ruby looks for methods on the ClassThatExtends object itself and finds module_method there.

5. Important result

ClassThatIncludes.module_method
# => NoMethodError

ClassThatExtends.new.module_method
# => NoMethodError

Each keyword affects a different receiver.

Inspecting ancestors

You can see part of this behavior directly:

module ReusableModule
  def module_method
  end
end

class ClassThatIncludes
  include ReusableModule
end

p ClassThatIncludes.ancestors
# => [ClassThatIncludes, ReusableModule, Object, Kernel, BasicObject]

This shows that ReusableModule is in the method lookup chain for instances of ClassThatIncludes.

Real World Use Cases

When to use include

Use include when every instance of a class should share common behavior.

Examples:

  • formatting methods for model objects
  • permission-checking behavior for service objects
  • reusable validation helpers
  • logging behavior for instances
  • comparable behavior like Enumerable
module Printable
  def print_name
    puts name
  end
end

class User
  include Printable

  attr_reader :name

  def initialize(name)
    @name = name
  end
end

When to use extend

Use extend when you want to add behavior to one specific object, often a class.

Examples:

  • class-level helper methods
  • configuration APIs
  • DSL-style macros
  • utility behavior on a single object
module FindByName
  def find_by_name(name)
    puts "Finding #{name}"
  end
end

class User
  extend FindByName
end

User.find_by_name("Alice")

Extending a regular object

extend is not limited to classes.

module Debuggable
  def debug
    "debug info"
  end
end

item = "hello"
item.extend(Debuggable)

puts item.debug
# => debug info

Only that one string object gets the method.

Take Quiz

Real Codebase Usage

In real Ruby projects, include and extend are often used in patterns rather than isolation.

1. Shared instance behavior with include

A common use is to keep classes small by moving reusable instance methods into modules.

module TimestampFormatter
  def formatted_time(time)
    time.strftime("%Y-%m-%d")
  end
end

class Report
  include TimestampFormatter
end

2. Class-level APIs with extend

Libraries often use extend to add class methods that act like macros.

module Configurable
  def setting(name, value)
    @settings ||= {}
    @settings[name] = value
  end

  def settings
    @settings || {}
  end
end

class AppConfig
  extend Configurable
  setting :timeout, 30
end

3. Using both together

A frequent pattern is:

  • include for instance methods
  • extend for class methods
module Trackable
  def track
    "instance tracking"
  end

  module ClassMethods
    def tracking_enabled?
      true
    end
  end

  def self.included(base)
    base.extend(ClassMethods)
  end
end

class Order
  include Trackable
end

puts Order.tracking_enabled?
puts Order.new.track

This pattern appears in many Ruby libraries and frameworks.

4. Guard clauses and validation helpers

Modules included into classes often centralize common checks.

module Validatable
  def validate_name!(name)
    raise ArgumentError, "name required" if name.to_s.strip.empty?
  end
end

5. DSL building

Ruby frameworks often extend classes with methods like:

  • has_many
  • before_action
  • validates

These are usually class-level methods added with extend directly or indirectly.

Common Mistakes

1. Thinking extend only works for classes

It works on any object.

module Extra
  def hello
    "hello"
  end
end

obj = Object.new
obj.extend(Extra)
puts obj.hello

2. Expecting include to create class methods

Broken example:

module Helper
  def do_work
    "done"
  end
end

class Task
  include Helper
end

Task.do_work
# NoMethodError

Fix

Call the method on an instance:

Task.new.do_work

Or use extend if you want a class method:

class Task
  extend Helper
end

3. Expecting instances to get methods from extend

Broken example:

module Helper
  def do_work
    "done"
  end
end

class Task
  extend Helper
end

Task.new.do_work
# NoMethodError

Fix

Use include for instance methods.

4. Mixing up module methods and mixed-in methods

This is a different thing:

module Tool
  def self.info
    "module-level method"
  end
end

Tool.info

def self.info creates a method on the module object itself. That method is not what include mixes into classes.

To mix in methods, define them like this instead:

module Tool
  def info
    "instance-style method for mixing in"
  end
end

5. Forgetting method lookup order

If a class and a module define the same method, the class method wins.

module Greeting
  def hello
    "from module"
  end
end

class Person
  include Greeting

  def hello
    "from class"
  end
end

puts Person.new.hello
# => from class

Know that mixins participate in Ruby's ancestor chain.

Comparisons

Featureincludeextend
Adds methods toInstances of a classThe receiver object itself
Common use in classesInstance methodsClass methods
Works on any object?Typically used in modules/classesYes
Affects ancestor chain?Yes, for instance method lookupYes, via singleton class
Typical purposeShared object behaviorClass-level or object-specific behavior

include vs prepend

Featureincludeprepend
Method lookup priorityClass methods come before module methodsModule methods come before class methods
Common useAdd reusable behaviorWrap or override behavior

include/extend vs module singleton methods

PatternMeaning
def method_name inside a moduleDefines a method that can be mixed in
def self.method_name inside a moduleDefines a method on the module object itself

Example:

module ExampleModule
  def mixed_in_method
    "mixed in"
  end

  def self.module_method
    "called on the module itself"
  end
end

puts ExampleModule.module_method
# => called on the module itself
Take Quiz

Cheat Sheet

# Define a module for mixing in
module MyModule
  def hello
    "hello"
  end
end

# include => instance methods
class A
  include MyModule
end
A.new.hello

# extend => methods on the object itself
class B
  extend MyModule
end
B.hello

Rules to remember

  • include adds module methods to instances of the class
  • extend adds module methods to the receiver itself
  • classes are objects too, so extend in a class body creates class methods
  • extend can be used on any object, not just classes
  • def self.name inside a module defines a module-level method, not a mixin method

Quick checks

ClassName.ancestors

Shows modules included for instance lookup.

object.singleton_class.ancestors

Can help inspect methods added by extend.

Common pattern for both instance and class methods

module Example
  def instance_method
    "instance"
  end

  module ClassMethods
    def class_method
      "class"
    end
  end

  def self.included(base)
    base.extend(ClassMethods)
  end
end

Edge case

If both the class and included module define the same method, the class version is used first.

FAQ

Is extend only for adding class methods in Ruby?

No. extend adds methods to any specific object. If that object is a class, the methods appear as class methods.

Why does include create instance methods?

Because the module is inserted into the class's ancestor chain for instance method lookup.

Can I use both include and extend with the same module?

Yes. Then the module's methods can be available both on instances and on the class object.

What is the difference between include and require in Ruby?

require loads a file. include mixes a module's methods into a class or module.

How do I add both instance and class methods from one module?

A common pattern is to include the module and, inside its included hook, extend a nested ClassMethods module.

Does include copy methods into the class?

Not exactly. Ruby uses the ancestor chain for method lookup rather than physically copying method definitions.

What happens if a class and an included module define the same method?

The class method takes priority over the included module method.

Take Quiz

Mini Project

Description

Build a small Ruby example that models a class with shared instance behavior and shared class-level behavior. This project demonstrates the practical difference between include and extend in a realistic way.

Goal

Create a User class where instances can format their names, and the class itself can describe its role using module-based behavior.

Requirements

  • Create one module for instance behavior
  • Create one module for class-level behavior
  • Use include for the instance behavior in the User class
  • Use extend for the class-level behavior in the User class
  • Show that instances and the class can call different methods
Take Quiz

Keep learning

Related questions

View more