Dart Mixins
last modified October 18, 2026
In this article, we show how to use mixins in Dart language. Mixins are a way to reuse code across multiple class hierarchies without using inheritance. They allow you to add functionality to a class without creating a full parent-child relationship.
Mixins are particularly useful when you want to share behavior between classes
that don't share a common ancestor. They are declared using the
mixin keyword and can be added to a class using the
with keyword. A class can use several mixins, but it can extend
only one class.
Dart Mixins Simple Example
The following example demonstrates how to create and use a simple mixin in Dart.
mixin Logging {
void log(String message) {
print('Log: $message');
}
}
class User with Logging {
String name;
User(this.name);
void greet() {
log('User $name says hello!');
}
}
void main() {
final user = User('Alice');
user.greet();
}
In this program, we define a mixin Logging that provides a
log method. We then use this mixin in the User class
to log a greeting message.
mixin Logging {
void log(String message) {
print('Log: $message');
}
}
We define a mixin named Logging that contains a log
method. A mixin cannot be instantiated and has no constructors.
class User with Logging {
We create a User class that uses the Logging mixin
with the with keyword. The greet method uses the
log method from the mixin as if it were declared in the class.
final user = User('Alice');
user.greet();
We create an instance of the User class and call the
greet method, which logs a message.
$ dart main.dart Log: User Alice says hello!
Dart Mixins with Multiple Classes
Mixins can be used with multiple classes to share common behavior. The classes
do not have to be related. A class also becomes a subtype of the mixin, so the
is operator works.
mixin Logging {
void log(String message) {
print('Log: $message');
}
}
class User with Logging {
String name;
User(this.name);
void greet() {
log('User $name says hello!');
}
}
class Admin with Logging {
String name;
Admin(this.name);
void announce() {
log('Admin $name makes an announcement!');
}
}
void main() {
final user = User('Alice');
user.greet();
final admin = Admin('Bob');
admin.announce();
print(user is Logging);
print(admin is User);
}
In this program, we use the Logging mixin in both the
User and Admin classes to share logging functionality.
The two classes are not related; the last line shows that an Admin
is not a User, but both are Logging.
$ dart main.dart Log: User Alice says hello! Log: Admin Bob makes an announcement! true false
Dart Mixins with Overriding
A class can override the methods it gets from a mixin. The members of the class take precedence over the members of the mixin.
mixin Logging {
void log(String message) {
print('Log: $message');
}
}
class User with Logging {
String name;
User(this.name);
@override
void log(String message) {
print('User Log: $message');
}
void greet() {
log('User $name says hello!');
}
}
void main() {
final user = User('Alice');
user.greet();
}
In this program, the User class overrides the log
method from the Logging mixin.
@override
void log(String message) {
print('User Log: $message');
}
The User class overrides the log method to provide
custom logging behavior. The @override annotation documents the
intent and lets the analyzer check it.
$ dart main.dart User Log: User Alice says hello!
Dart Mixins with state
Mixins can declare fields too. Each class that uses the mixin gets its own copy of the fields.
mixin Counter {
int _count = 0;
int get count => _count;
void increment() => _count++;
}
class Clicker with Counter {}
class Visitor with Counter {}
void main() {
final a = Clicker();
final b = Visitor();
a.increment();
a.increment();
b.increment();
print(a.count);
print(b.count);
}
The Counter mixin keeps the state in a private field. The two
objects have independent counters.
$ dart main.dart 2 1
Dart Mixins with Constraints
Mixins can specify constraints using the on keyword to restrict
their usage to subclasses of a specific class (or implementations of a type).
The mixin can then use the members of that class, and call the members of
the superclass with super.
class Person {
String name;
Person(this.name);
}
mixin Logging on Person {
void log(String message) {
print('Log: $name says $message');
}
}
class User extends Person with Logging {
User(super.name);
void greet() {
log('Hello!');
}
}
void main() {
final user = User('Alice');
user.greet();
}
In this program, the Logging mixin is constrained to be used only
with classes that extend Person. Using it elsewhere is a
compile-time error.
mixin Logging on Person {
void log(String message) {
print('Log: $name says $message');
}
}
The Logging mixin uses the on keyword to specify that
it can only be used with classes that extend Person. Thanks to the
constraint, the mixin can access the name property.
class User extends Person with Logging {
User(super.name);
The User class extends Person and uses the
Logging mixin. The constructor passes the name to the superclass
with a super parameter.
$ dart main.dart Log: Alice says Hello!
Dart Mixins with multiple mixins
A class can use several mixins: class C with A, B. If the mixins
define the same member, the last one wins. When the mixins call
super, the calls are chained in the order of declaration (from
right to left), which is called linearization.
class Base {
String describe() => 'Base';
}
mixin A on Base {
@override
String describe() => 'A -> ${super.describe()}';
}
mixin B on Base {
@override
String describe() => 'B -> ${super.describe()}';
}
class C extends Base with A, B {}
class D extends Base with B, A {}
void main() {
print(C().describe());
print(D().describe());
}
In C, the mixin B is applied last, so its method is
called first and its super call reaches A, and then
Base. Reversing the order in D reverses the chain.
$ dart main.dart B -> A -> Base A -> B -> Base
Dart mixin class
Since Dart 3, a declaration can be marked as both a class and a mixin with
mixin class. It can be extended as a class and mixed in with
with. A plain mixin can only be mixed in, and a plain
class can no longer be used as a mixin (unless it is declared as
mixin class).
mixin class Walker {
void walk() => print('walking');
}
class Dog with Walker {}
class Person extends Walker {}
void main() {
Dog().walk();
Person().walk();
Walker().walk();
}
The Walker declaration can be used as a mixin (Dog),
as a superclass (Person), and instantiated directly. A
mixin class cannot have a constructor with parameters, nor an
extends or with clause.
$ dart main.dart walking walking walking
Source
Dart Mixins - Language Documentation
In this article, we have covered the basics of using mixins in Dart. Mixins are a powerful feature for code reuse and can be used to share behavior across multiple classes.
Author
List all Dart tutorials.