Dart Optional Parameters: Beginner-Friendly Guide with Examples

David Martin

Have you ever written a Dart or Flutter function where not every argument feels necessary every single time? For example, you may want to greet a user with their name, but sometimes you also want to add a title like “Dr.” or “Professor.” Do you really need two separate functions for that?

This is where optional parameters come in. They let you define functions that accept extra inputs only when needed, without forcing them every time. In short, optional parameters make your functions more flexible and easier to read, while still keeping the code clean and predictable.

Note: The code examples in this article are simplified for explanation and learning purposes. They are not production-ready and should be treated as a reference only.

free trial banner

Optional Positional Parameters

In Dart, you can make parameters optional by wrapping them in square brackets [ ]. These are called optional positional parameters because their values are identified by the order in which you pass them. If you don’t provide a value, the parameter defaults to null unless you assign a default value.

String greet(String name, [String? title]) {
  if (title != null) {
    return 'Hello $title $name!';
  }
  return 'Hello $name!';
}

void main() {
  print(greet('Alice'));                 // Hello Alice!
  print(greet('John', 'Professor'));     // Hello Professor John!
}

Here, the second parameter title is optional. If you omit it, Dart automatically treats it as null. You can also set a default value:

String greet(String name, [String title = 'Guest']) {
  return 'Hello $title $name!';
}

This way, calling greet('Alice') prints Hello Guest Alice! without extra checks.

Optional Named Parameters

Instead of relying on position, Dart also allows you to define parameters inside curly braces { }, known as optional named parameters. When calling the function, you specify the parameter names explicitly, which makes the call more readable and avoids mistakes from passing arguments in the wrong order.

String greet({required String name, String title = ''}) {
  if (title.isEmpty) {
    return 'Hello $name!';
  }
  return 'Hello $title $name!';
}

void main() {
  print(greet(name: 'Alice'));                       // Hello Alice!
  print(greet(name: 'John', title: 'Professor'));    // Hello Professor John!
}

In this example, a name is required while the title is optional, with a default empty string. This way, calling greet(name: ‘Alice’) prints Hello Alice! without needing extra checks, and adding title: ‘Professor’ produces Hello Professor John!

Named parameters give you flexibility to only pass what’s needed and to call functions in a more descriptive way.

Default Values for Optional Parameters

When an optional parameter isn’t provided, Dart assigns it a default of null. This can lead to extra null checks inside your function. To avoid that, you can assign a compile-time constant as a default value. Default values work for both positional and named optional parameters.

String greet({required String name, String title = 'Guest'}) {
  return 'Hello $title $name!';
}

void main() {
  print(greet(name: 'Alice'));             // Hello Guest Alice!
  print(greet(name: 'Bob', title: 'Dr.')); // Hello Dr. Bob!
}

Here, the title defaults to “Guest” if not provided. Calling greet(name: ‘Alice’) prints Hello Guest Alice!, while overriding the title prints Hello Dr. Bob!.

Note: Default values must be compile-time constants. This means you can use literals (like strings, numbers, booleans) or const constructors, but not runtime values such as DateTime.now().

Wrapping Up

Optional parameters in Dart make your functions more flexible and concise. By using positional, named, and default values, you can reduce boilerplate code and make function calls easier to read. 

Each approach serves its own purpose: positional parameters keep things simple, named parameters improve clarity, and default values help you avoid unnecessary null checks.

As a best practice, choose the type of optional parameter that matches the intent of your function. Use positional when order is obvious, named when readability matters, and defaults when you want predictable behavior without extra checks.