skip to content

In Dart, what does the required modifier on a named parameter guarantee, and how does it interact with nullability and default values?

level: juniorimportance: should knowfreq 58%

answer

  1. named but not optional
  2. caller must pass it
  3. independent of nullability
  4. no default alongside required
  5. @required annotation is history

basics

~20 s

required makes a named parameter mandatory: a call that omits it is a compile error. It is independent of nullability, so required int? is legal and callers must pass null explicitly, but a required parameter cannot also have a default value.

solid answer

~40 s

Named parameters are optional by default, and under null safety an optional parameter must either be nullable or have a default, because an omitted argument would otherwise be `null`. `required` fills the missing corner: a parameter that is **named but mandatory**. Omitting it is a compile error (`missing_required_argument`), so a non-nullable named parameter needs no default. `required` and nullability are separate: `required Widget? child` forces the caller to decide, even if the decision is `null`. A default value is pointless on a required parameter and is rejected (`default_value_on_required_parameter`). Before null safety, the `@required` annotation from `package:meta` was only an analyzer hint; the Dart 3.10 analyzer removed support for it, so the keyword is the only form.

code

dart · 14 lines
dart
class Greeting {
  const Greeting({required this.name, required this.title, this.suffix = '!'});

  final String name;
  final String? title; // required, but may be null
  final String suffix;

  String render() => '${title ?? ''} $name$suffix'.trim();
}

void main() {
  print(const Greeting(name: 'Ada', title: null).render()); // Ada!
  print(const Greeting(name: 'Ada', title: 'Dr').render()); // Dr Ada!
}

go deeper

for a junior

Recall that required forces callers to pass a named argument and that omitting it fails at compile time.

for a middle

Explain why optional parameters must be nullable or defaulted under null safety, and why required and ? answer different questions.

for a senior

Design constructors so that missing inputs are compile errors, choosing between required T, required T?, and a default deliberately.

for a principal

Set API conventions for public packages: which parameters are required, which defaulted, and how adding a required parameter breaks every caller.

## The gap `required` fills Dart has **positional** and **named** parameters, and each can be **mandatory** or **optional**. Before null safety, three of the four combinations had syntax; named-and-mandatory did not: | | mandatory | optional | |---|---|---| | positional | `f(int x)` | `f([int? x])` | | named | `f({required int x})` | `f({int? x})` or `f({int x = 0})` | With null safety an omitted optional argument would silently be `null`, so an optional parameter must be **nullable or have a default value**. That left no way to declare a named, non-nullable parameter without a default — until `required` arrived with null safety and filled the corner. ## What `required` guarantees - Every call **must pass the argument by name**; omitting it is a compile error reported as `missing_required_argument`. - Because the caller always supplies a value, a **non-nullable** type needs no default: `{required String name}` is complete. - The guarantee is **static**. Nothing is checked at runtime, and there is no way to call the function without the argument in sound code. ```dart void connect({required String host, int port = 443, String? proxy}) {} void main() { connect(host: 'example.test'); // ok connect(host: 'example.test', port: 8443); // ok // connect(port: 80); // error: missing_required_argument } ``` ## Required-ness is independent of nullability It is easy to conflate the two, but they answer different questions: 1. **Must the caller mention this parameter?** — `required` answers that. 2. **May the value be absent?** — the `?` in the type answers that. So all combinations are legal and mean different things: - `{required int x}` — caller must pass a real `int`. - `{required int? x}` — caller must pass something, possibly an explicit `null`. Useful when forgetting the argument is a bug but `null` is a meaningful choice. - `{int x = 0}` — caller may omit it and gets `0`. - `{int? x}` — caller may omit it and gets `null`. The Dart language tour illustrates this with a Flutter widget constructor, `const Scrollbar({super.key, required Widget child})`, and notes that `required Widget? child` is also valid. ## What is rejected - **`required` with a default value** — `{required String message = 'x'}` is an error (`default_value_on_required_parameter`); the default could never be used. - **`required` on a positional parameter** — positional parameters are already mandatory unless placed in `[]`, and the modifier only applies inside `{}`. ## History: the `@required` annotation Before null safety, Flutter code marked mandatory named parameters with the **`@required` annotation** from `package:meta`. It was only a hint: the analyzer warned, but a caller could still omit the argument and receive `null`. With null safety the **keyword** replaced it, and the Dart 3.10 analyzer **removed support** for the deprecated annotation. Code that still uses `@required` should switch to the keyword. ## Design guidance - Prefer `required` over a nullable parameter plus a runtime `ArgumentError` check: the compiler then enforces the contract at every call site. - Use `required T?` sparingly, when a caller must consciously choose absence. - Keep constructors of widgets and value objects explicit: `required this.title` makes a missing field a compile error rather than a bug found at runtime. - Since Dart 3.12, a named initializing formal may target a private field, so `Point({required this._x})` is legal and callers still write `Point(x: 1)`.

  • In Dart, when would you declare a parameter as `required T?` rather than `T?`?
    When omitting the argument is likely a mistake but `null` is a legitimate value. `required` forces every caller to state a value, so a forgotten argument becomes a compile error, while `T?` still allows an explicit `null`. With plain `T?`, forgetting the argument and choosing `null` look identical.
  • In Dart, what happened to the @required annotation from package:meta?
    It predated null safety and only produced an analyzer hint, so a caller could still omit the argument and pass `null` implicitly. The `required` keyword replaced it with a compile-time guarantee, and the Dart 3.10 analyzer removed support for the old annotation, so code must use the keyword.

saying these in an interview costs you the question

  • required makes a parameter non-nullable automatically
  • A required named parameter can still have a default value as a fallback
  • required is checked at runtime and throws if the argument is missing
  • A nullable named parameter can never be marked required
  • @required from package:meta is the current way to mark named parameters