last modified May 29, 2026
The Stdin class in Dart represents the standard input stream. It is
part of Dart's dart:io library and is accessed through the top-level
stdin variable. It is essential for interactive command-line
applications.
Stdin extends Stream<List<int>>, so it can
be consumed as a byte stream using the full Dart stream API. It also provides
synchronous convenience methods — readLineSync and
readByteSync — for simpler sequential input.
Stdin is a class that implements
Stream<List<int>>. It is accessed through the
stdin top-level variable exported by dart:io.
The corresponding stdout and stderr variables handle
output and error messages.
The two primary synchronous methods are readLineSync, which reads a
complete line, and readByteSync, which reads a single byte. For
asynchronous consumption, stdin can be transformed with
utf8.decoder and LineSplitter from
dart:convert.
This example reads a single line of text from the console using
readLineSync.
import 'dart:io';
void main() {
stdout.write('Enter your name: ');
String name = stdin.readLineSync() ?? 'Unknown';
print('Hello, $name!');
}
readLineSync blocks until the user presses Enter and returns the
line as a String, or null if EOF is reached. The
?? operator supplies a fallback value. stdout.write is
used for the prompt so the cursor stays on the same line as the user's input.
$ dart main.dart Enter your name: John Hello, John!
This example reads two integers from the console and prints their sum.
import 'dart:io';
void main() {
stdout.write('Enter first number: ');
var num1 = int.tryParse(stdin.readLineSync() ?? '0') ?? 0;
stdout.write('Enter second number: ');
var num2 = int.tryParse(stdin.readLineSync() ?? '0') ?? 0;
print('Sum: ${num1 + num2}');
}
readLineSync always returns a String?, so numeric
input must be parsed explicitly. int.tryParse returns
null for non-numeric strings instead of throwing an exception,
allowing the ?? operator to substitute a safe default.
$ dart main.dart Enter first number: 12 Enter second number: 7 Sum: 19
This example reads lines from stdin asynchronously by treating it as a byte
stream and applying decoders from dart:convert.
import 'dart:convert';
import 'dart:io';
void main() async {
stdout.writeln('Type lines to echo in upper case (Ctrl+D to finish):');
final lineStream = stdin
.transform(utf8.decoder)
.transform(const LineSplitter());
await for (final line in lineStream) {
stdout.writeln(line.toUpperCase());
}
}
stdin implements Stream<List<int>>.
Chaining utf8.decoder converts raw byte chunks into strings, and
LineSplitter splits the decoded text into individual lines. The
await for loop processes each line as it arrives and exits when
stdin closes (Ctrl+D on Unix/macOS, Ctrl+Z then Enter on Windows).
$ dart main.dart Type lines to echo in upper case (Ctrl+D to finish): hello HELLO dart DART
This example demonstrates reading raw bytes from standard input.
import 'dart:io';
void main() {
stdout.writeln('Press any key to continue...');
var byte = stdin.readByteSync();
print('You pressed: $byte (${String.fromCharCode(byte)})');
}
readByteSync reads a single byte synchronously and returns its
value as an int, or -1 at EOF.
String.fromCharCode converts the integer back to its printable
character. This is useful for single-keypress menus or byte-by-byte input
processing.
$ dart main.dart Press any key to continue... a You pressed: 97 (a)
This example reads all lines from stdin until EOF and prints a summary.
import 'dart:io';
void main() {
print('Enter multiple lines (Ctrl+D to end):');
var lines = <String>[];
while (true) {
var line = stdin.readLineSync();
if (line == null) break;
lines.add(line);
}
print('You entered ${lines.length} lines:');
lines.forEach(print);
}
readLineSync returns null when EOF is reached
(Ctrl+D on Unix/macOS, Ctrl+Z then Enter on Windows). Collecting each non-null
line into a list and breaking on null is the standard synchronous
pattern for consuming all of stdin, whether from an interactive terminal or a
piped file.
$ dart main.dart Enter multiple lines (Ctrl+D to end): hello world dart You entered 3 lines: hello world dart
This example reads a line with an explicit UTF-8 encoding to correctly handle non-ASCII characters such as accented letters or CJK characters.
import 'dart:convert';
import 'dart:io';
void main() {
stdout.write('Enter your name: ');
final name = stdin.readLineSync(encoding: utf8) ?? 'Unknown';
print('Hello, $name!');
print('Character count: ${name.length}');
}
readLineSync accepts an optional encoding parameter.
Passing utf8 from dart:convert correctly decodes
multi-byte characters. Without an explicit encoding, the system default is
used, which may not handle all Unicode on every platform.
$ dart main.dart Enter your name: Ján Hello, Ján! Character count: 3
This example repeatedly prompts the user until a valid positive integer is entered.
import 'dart:io';
int readPositiveInt(String prompt) {
while (true) {
stdout.write(prompt);
final input = stdin.readLineSync()?.trim() ?? '';
final value = int.tryParse(input);
if (value != null && value> 0 && value < 130) return value;
stderr.writeln('Please enter a valid positive integer (1-129).');
}
}
void main() {
final age = readPositiveInt('Enter your age: ');
print('In ten years you will be ${age + 10}.');
}
The helper function loops until int.tryParse succeeds and the value
is within the valid range (1-129). Invalid attempts print an error to
stderr and repeat the prompt. The return type is non-nullable
int because the loop only exits through the return
statement.
$ dart main.dart Enter your age: hello Please enter a valid positive integer (1-129). Enter your age: -3 Please enter a valid positive integer (1-129). Enter your age: 25 In ten years you will be 35.
readLineSync returns null at EOF; always handle it with ?? or an explicit null checkint.tryParse and double.tryParse over parse to avoid exceptions on bad inputencoding: utf8 to readLineSync when expecting non-ASCII charactersstdin.transform(utf8.decoder).transform(const LineSplitter()) with await for for non-blocking stream processing
This tutorial covered Dart's Stdin class with practical examples
demonstrating single-line reading, numeric parsing, asynchronous stream
processing, raw byte reading, EOF handling, UTF-8 encoding, and input
validation loops.
My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.
List all Dart tutorials.